Enhancement: Support all kwargs for `model_dump` in PydanticPlugin
Summary
litestar.contrib.pydantic.PydanticPlugin has the argument prefer_alias which sets the by_alias argument of the created Pydantic type encoders. The type encoders are based on pydantic.BaseModel.model_dump which also has the arguments exclude_none and exclude_defaults. This enhancement suggests to add similar arguments to PydanticPlugin to configure the type encoders.
Basic Example
import pydantic
import typing
import litestar
import litestar.contrib.pydantic
class MyModel(pydantic.BaseModel):
some_number: int = pydantic.Field(alias="someNumber")
title: str = "a number"
comment: typing.Optional[str] = None
@litestar.get("/")
def get_stuff() -> MyModel:
return MyModel(some_number=42)
app = litestar.Litestar(
route_handlers=[get_stuff],
plugins=[
litestar.contrib.pydantic.PydanticPlugin(
prefer_alias=True,
# NOTE: The argument names are just provisional
exclude_none=True, # new
exclude_defaults=True, # new
)
],
)
A GET request to / would return {"someNumber":42} because of the plugin configuration. Without it, it would return {"some_number":42,"title":"a number","comment":null}.
Drawbacks and Impact
You can currently achieve the same result without this feature by adding a custom type encoder for pydantic.BaseModel. However, it must be combined with PydanticPlugin for the generated schema to use aliases.
import pydantic
import typing
import litestar
import litestar.contrib.pydantic
class MyModel(pydantic.BaseModel):
some_number: int = pydantic.Field(alias="someNumber")
title: str = "a number"
comment: typing.Optional[str] = None
@litestar.get("/")
def get_stuff() -> MyModel:
return MyModel(some_number=42)
app = litestar.Litestar(
route_handlers=[get_stuff],
plugins=[litestar.contrib.pydantic.PydanticPlugin(prefer_alias=True)],
type_encoders={
pydantic.BaseModel: lambda x: x.model_dump(mode="json", by_alias=True, exclude_none=True, exclude_default=True),
},
)
Therefore, the only purpose of this enhancement is to make this use case (which I believe to be a common one) simpler to express in code by making the plugin able to do more, reducing the need for type encoders. The community must decide if this is desirable or not.
As long as the default values of the new arguments match the old behavior, this should not cause any issues with backwards compatibility.
Unresolved questions
I can see that there may be concerns about having to support a growing list of pydantic.BaseModel.model_dump arguments (for example exlude_unset). I believe that concern to be valid, but you could always draw a line and say "the plugin supports these extremely common arguments, if you want more, use a custom type encoder". Still, the concern is valid and I believe it should be part of the discussion.
[!NOTE]
While we are open for sponsoring on GitHub Sponsors and OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.Check out all issues funded or available for funding on our Polar.sh dashboard
- If you would like to see an issue prioritized, make a pledge towards it!
- We receive the pledge once the issue is completed & verified
- This, along with engagement in the community, helps us know which features are a priority to our users.
I think it's reasonable to include not just the ones mentioned, but all the arguments supported by model_dump. There's only 6 arguments to model_dump that we would need to take from the user.
"Closes X and Y" apparently does not cause Y to be closed, so I am closing it here.
Thanks!