Closed gitgithan closed 1 year ago
I'm not sure what your question is here but to be more clear about exclude_unset
: it's a way to tell Pydantic to give us only the fields that were actually given in the request and discard the others.
So if we have a model like this:
class PostPartialUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
And we make this request:
{"title": "hello"}
Here is what we get without and with exclude_unset
:
updated_fields = post_update.dict()
print(updated_fields) # {"title": "hello", "content": None}
updated_fields = post_update.dict(exclude_unset=True)
print(updated_fields) # {"title": "hello"}
With exclude_unset
, only title
is output in the dictionary, not content
.
This is useful for partial updates, when we want to update only a subset of fields without having to repeat the fields that are not changing.
It's important because when we're doing this:
updated_post = post_db.copy(update=updated_fields)
We override every fields set in updated_fields
.
In your experiment with exclude_unset=False
, updated_fields
was {"title": "hello", "content": None}
. Hence, we also set content
to None
. This is not valid for the PostPublic
, because content
is required and can't be None
, hence the error you were getting.
Thanks for this example. I was initially doubting the code provided was able to handle incomplete inputs (not having both the 2 keys mentioned in PostPartialUpdate
) like
because i received internal server error.
Later i realized that was because i set exclude_unset=False
when testing incomplete inputs.
If i had left exclude_unset=True
as given, there's nothing wrong with the code in handling incomplete inputs.
Yes, with exclude_unset=False
, that's totally expected :)
Cheers!
Edit
Below is no longer an issue. My confusion arose because I set
exclude_unset=False
to investigate its effects, then gave only{"title": "string"}
when calling the endpoint. This combination leads to Internal Server Error which prompted this issue. If we do it properly by settingexclude_unset=True
, there are no issues with the question belowNevertheless the investigations on effects of
exclude_unset=False
could be helpful to other readers. There are 2 independent dimensions of experimentationThis post is half error reporting and half what I wish was explained better.
I was testing
chapter4_working_pydantic_objects_05.py
. First I edited the file to set up dummy data because it was empty and cannot be tested (will always get 404)Then from automated docs, I called the endpoint with
{"title": "string"}
, intentionally leaving out content key that was suggested by the docs (or else cannot see effect ofexclude_unset=True
).Then terminal errors with
I guess this is because
PostPublic
which was inherited fromPostBase
which hadcontent:str
type which did not allow None.Question: So how do we make this work? (To allow user to call update endpoint with only title, with only content, and with none of both?). Making fields in
PostBase
optional doesn't seem like the correct way to handle this.On a separate but related issue, this lesson could have been clearer on how a user could understand the effects of
exclude_unset=True
. To look at what this parameter is doing, and to solve the above issue, Iresponse_model=PostPublic
from the path decorator so it doesn't constrain response types (which solves this issue, probably wrongly though)print(updated_fields)
to the code{"title": "string"}
(you won't see the effect ofexclude_unset
if you used default{"title": "string", "content": "string"}
suggested by automated docs)Response Body:
exclude_unset=True
print(updated_fields)
gives{'title': 'string'}
exclude_unset=False (default)
print(updated_fields)
gives{'title': 'string', 'content': None}
Explanation When
exclude_unset=False
, the update endpoint was not givencontent
key when called.PostPartialUpdate
did not exclude what was unset/not given (content), so it filled in content with None fromcontent: Optional[str] = None
. Thiscontent:None
was then put into the response throughpost_db.copy(update=updated_fields)
. Whenexclude_unset=True
, the update endpoint was also not given thecontent
key when called.PostPartialUpdate
excluded what was not unset/not given (content), soupdated_fields
contains only the title, leavingcontent
as the original hardcoded value