Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #246 #248

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion piccolo_api/crud/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def _pydantic_model_output(
include_readable=include_readable,
include_columns=include_columns,
model_name=f"{self.table.__name__}Output",
nested=nested,
nested=nested, **self.schema_extra,
)

@property
Expand All @@ -337,6 +337,7 @@ def pydantic_model_optional(self) -> t.Type[pydantic.BaseModel]:
include_default_columns=True,
all_optional=True,
model_name=f"{self.table.__name__}Optional",
**self.schema_extra,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the slow reply and sorry if I missed your point and doing something wrong, but this will break the PATCH request. I tried something like this

class Message(Table, db=DB):
    message_title = Varchar(length=100)
    message_content = Varchar()

app = FastAPI(debug=True)

def to_camel(string: str) -> str:
    string_split = string.split("_")
    return string_split[0] + "".join(
        word.capitalize() for word in string_split[1:]
    )

class MyConfig(pydantic.BaseConfig):
    alias_generator = to_camel
    allow_population_by_field_name = True

FastAPIWrapper(
    root_url="/message/",
    fastapi_app=app,
    piccolo_crud=PiccoloCRUD(
        table=Message,
        read_only=False,
        schema_extra={"pydantic_config_class": MyConfig},
    ),
)

and I get a 400 error on the PATCH request Unrecognized keys - {'messageContent', 'messageTitle'} (using curl) because the camelCase field is not recognized.
Also PUT request get 500 error (with that Pydantic configuration of camelCase in schema_extra) with mesage AttributeError: type object 'Message' has no attribute 'messageTitle'
Can you confirm that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry, better late than never xD. Yes, I saw. I didn't quite understand these 3 data variables/params in the following lines:

@apply_validators
@db_exception_handler
async def put_single(
self, request: Request, row_id: PK_TYPES, data: t.Dict[str, t.Any]
) -> Response:
"""
Replaces an existing row. We don't allow new resources to be created.
"""
cleaned_data = self._clean_data(data)
try:
model = self.pydantic_model(**cleaned_data)
except ValidationError as exception:
return Response(str(exception), status_code=400)
cls = self.table
values = {
getattr(cls, key): getattr(model, key) for key in data.keys()
}
try:
await cls.update(values).where(
cls._meta.primary_key == row_id
).run()
return Response(status_code=204)
except ValueError:
return Response("Unable to save the resource.", status_code=500)

cleaned_data
data
model

If I change the code like below we can achieve something:

values = {
  getattr(cls, key): getattr(model, key) for key in model.dict().keys()
}

ie new problems:
image
Can you test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to explain (as I understand it) and I hope it will be clear enough :).

cleaned_data - payload handling null value (convert null as string in payload to None)
data - payload data
model - Pydantic model

The tests fail on the PATCH request (partial update) because data dict are not the same as model.dict(), because the model uses pydantic_model_optional which puts the optional fields as None and if we patch only one field we need data from payload not from model.
Example of payload data:

{'name': 'Star Wars: A New Hope'} <-- data dict
{'id': None, 'name': 'Star Wars: A New Hope', 'rating': None} <-- model.dict()

and because of that we get error 422 in patch tests if we use

values = {
  getattr(cls, key): getattr(model, key) for key in model.dict().keys()
}

)

def pydantic_model_plural(
Expand All @@ -355,6 +356,7 @@ def pydantic_model_plural(
include_columns=include_columns,
model_name=f"{self.table.__name__}Item",
nested=nested,
**self.schema_extra,
)
return pydantic.create_model(
str(self.table.__name__) + "Plural",
Expand Down