I want to allow users to selectively update fields using PUT calls. On the pydantic model, I have made the fields Optional. In the FastAPI handler if the model attribute is None, then the field was not given and I do not update it.
The problem with this approach is that there is no way for the client to "blank out" a field that isn't required for certain types.
In particular, I have date fields that I want clients to be able to clear by sending in a null in the JSON. How can I detect the difference between the client sending null or the client not sending the field/value at all? The model attribute is just None in either case.
Pydantic V2 is available since June 30, 2023
The .dict()
method has been removed in V2. In order to get a dictionary out of a BaseModel
instance, one must use the model_dump()
method instead:
from __future__ import annotations
from pydantic import BaseModel
class MyModel(BaseModel):
foo: int | None = None
bar: int | None = None
baz = MyModel(foo=None)
assert baz.model_dump(exclude_unset=True) == {"foo": None}
baz = MyModel(bar=None)
assert baz.model_dump(exclude_unset=True) == {"bar": None}
The pydantic documentation desccribes two options that can be used with the .dict()
method of models.
exclude_unset
: whether fields which were not explicitly set when creating the model should be excluded from the returned dictionary; default False. Prior to v1.0, exclude_unset was known as skip_defaults; use of skip_defaults is now deprecated
exclude_defaults
: whether fields which are equal to their default values (whether set or otherwise) should be excluded from the returned dictionary; default False
So you can create a model class with optional fields:
from typing import Optional
from pydantic import BaseModel
class MyModel(BaseModel):
foo: Optional[int] = None
bar: Optional[int] = None
And still generate a dict with fields explicitely set to None, but without default values:
baz = MyModel(foo=None)
assert baz.dict(exclude_unset=True) == {"foo": None}
baz = MyModel(bar=None)
assert baz.dict(exclude_unset=True) == {"bar": None}