-
Add support for Pydantic's ORM mode:
- Updated documentation about SQL with SQLAlchemy, using Pydantic models with ORM mode, SQLAlchemy models with relations, separation of files, simplification of code and other changes. New docs: SQL (Relational) Databases.
- The new support for ORM mode fixes issues/adds features related to ORMs with lazy-loading, hybrid properties, dynamic/getters (using
@property
decorators) and several other use cases. - This applies to ORMs like SQLAlchemy, Peewee, Tortoise ORM, GINO ORM and virtually any other.
- If your path operations return an arbitrary object with attributes (e.g.
my_item.name
instead ofmy_item["name"]
) AND you use aresponse_model
, make sure to update the Pydantic models withorm_mode = True
as described in the docs (link above). - New documentation about receiving plain
dict
s as request bodies: Bodies of arbitrarydict
s. - New documentation about returning arbitrary
dict
s in responses: Response with arbitrarydict
. - Technical Details:
- When declaring a
response_model
it is used directly to generate the response content, from whatever was returned from the path operation function. - Before this, the return content was first passed through
jsonable_encoder
to ensure it was a "jsonable" object, like adict
, instead of an arbitrary object with attributes (like an ORM model). That's why you should make sure to update your Pydantic models for objects with attributes to useorm_mode = True
. - If you don't have a
response_model
, the return object will still be passed throughjsonable_encoder
first. - When a
response_model
is declared, the sameresponse_model
type declaration won't be used as is, it will be "cloned" to create an new one (a cloned PydanticField
with all the submodels cloned as well). - This avoids/fixes a potential security issue: as the returned object is passed directly to Pydantic, if the returned object was a subclass of the
response_model
(e.g. you return aUserInDB
that inherits fromUser
but contains extra fields, likehashed_password
, andUser
is used in theresponse_model
), it would still pass the validation (becauseUserInDB
is a subclass ofUser
) and the object would be returned as-is, including thehashed_password
. To fix this, the declaredresponse_model
is cloned, if it is a Pydantic model class (or contains Pydantic model classes in it, e.g. in aList[Item]
), the Pydantic model class(es) will be a different one (the "cloned" one). So, an object that is a subclass won't simply pass the validation and returned as-is, because it is no longer a sub-class of the clonedresponse_model
. Instead, a new Pydantic model object will be created with the contents of the returned object. So, it will be a new object (made with the data from the returned one), and will be filtered by the clonedresponse_model
, containing only the declared fields as normally.
- When declaring a
- PR #322.
-
Remove/clean unused RegEx code in routing. PR #314 by @dmontagu.
-
Use default response status code descriptions for additional responses. PR #313 by @duxiaoyao.