Package: drf-pydantic
Use pydantic with Django REST frameworkIntroductionPerformanceInstallationUsageGeneralExisting ModelsNested ModelsManual Serializer ConfigurationPer-Field ConfigurationCustom SerializerIntroductionPydanticis a Python library used to perform
data serialization and validation.Django REST frameworkis a framework built
on top ofDjangoused to write REST APIs.If you develop DRF APIs and rely on pydantic for data validation/(de)serialization ,
thendrf-pydanticis for you 😍.ℹ️INFO>drf_pydanticsupportspydanticv2. Due to breaking API changes inpydanticv2 support forpydanticv1 is available only indrf_pydantic1.*.*.PerformanceTranslation betweenpydanticmodels andDRFserializers is done during class
creation (e.g., when you first import the model). This means that there will be
zero impact on the performance of your application
(server instance or serverless session)
when usingdrf_pydanticwhile your application is running.Installationpipinstalldrf-pydanticUsageGeneralUsedrf_pydantic.BaseModelinstead ofpydantic.BaseModelwhen creating your
models:fromdrf_pydanticimportBaseModelclassMyModel(BaseModel):name:straddresses:list[str]MyModel.drf_serializerwould be equvalent to the following DRF Serializer class:classMyModelSerializer:name=CharField(allow_null=False,required=True)addresses=ListField(allow_empty=True,allow_null=False,child=CharField(allow_null=False),required=True,)Whenever you need a DRF serializer you can get it from the model like this:my_value=MyModel.drf_serializer(data={"name":"Van",addresses:["Gym"]})my_value.is_valid(raise_exception=True)ℹ️INFOModels created usingdrf_pydanticare fully idenditcal to those created bypydantic. The only change is the addition of thedrf_serializerattribute.Existing ModelsIf you have an existing code base and you would like to add thedrf_serializerattribute only to some of your models, then I have great news 🥳 - you can easily
extend your existingpydanticmodels by addingdrf_pydantic.BaseModelto the list
of parent classes of the model you want to extend.Your existing pydantic models:frompydanticimportBaseModelclassPet(BaseModel):name:strclassDog(Pet):breed:strUpdate yourDogmodel and get serializer via thedrf_serializer:fromdrf_pydanticimportBaseModelasDRFBaseModelfrompydanticimportBaseModelclassPet(BaseModel):name:strclassDog(DRFBaseModel,Pet):breed:strDog.drf_serializer⚠️ATTENTIONInheritance order is important:drf_pydantic.BaseModelmust always go before
thepydantic.BaseModelclass.Nested ModelsIf you have nested models and you want to generate serializer only from one of them,
you don't have to update all models - only update the model you need,drf_pydanticwill generate serializers for all normal nestedpydanticmodels for free 🥷.fromdrf_pydanticimportBaseModelasDRFBaseModelfrompydanticimportBaseModelclassApartment(BaseModel):floor:inttenant:strclassBuilding(BaseModel):address:straparments:list[Apartment]classBlock(DRFBaseModel):buildings:list[Buildind]Block.drf_serializerManual Serializer ConfigurationIfdrf_pydanticdoes not generate the serializer you need, you can either granularly
configure which DRF serializer fields to use for each pydantic field, or you can
create a custom serializer for the model altogether.⚠️WARNINGWhen manually configuring the serializer you are responsible for setting all
properties of the fields (e.g.,allow_null,required,default, etc.).drf_pydanticdoes not perform any introspection for fields that are manually
configured or for any fields if a custom serializer is used.Per-Field ConfigurationfromtypingimportAnnotatedfromdrf_pydanticimportBaseModelfromrest_framework.serializersimportIntegerFieldclassPerson(BaseModel):name:strage:Annotated[float,IntegerField(min_value=0,max_value=100)]Custom SerializerIn example below,Personwill useMyCustomSerializeras its drf serializer.Employeewill have its own serializer generated bydrf_pydanticbecause it
does not have a user-defineddrf_serializerattribute (it's never inherited).Companywill have its own serializer generated bydrf_pydanticand it will usePerson's manually-defined serializer for itsceofield.fromdrf_pydanticimportBaseModelfromrest_framework.serializersimportSerializerclassMyCustomSerializer(Serializer):name=CharField(allow_null=False,required=True)age=IntegerField(allow_null=False,required=True)classPerson(BaseModel):name:strage:floatdrf_serializer=MyCustomSerializerclassEmployee(Person):salary:floatclassCompany(BaseModel):ceo:Person