How to Create Custom Serializer Fields in Django REST Framework
Python Django REST Framework provides a flexible way of converting python objects to JSON and that is by using a serializer class. The Serializer class serializes the data and returns a dictionary which can easily be converted to JSON.
The Serializers has many roles to perform such as validation, extraction of data from python objects to JSON, and also saving the data into the database.
In simple words, serializers are similar to the Django Forms with a difference as forms return HTML data whereas serializers return a dictionary that can be parsed to JSON.
A basic serializer can have at least one of these two methods create and save method. The method save()
is called during saving and the other two additional methods create
and update
can also be used to isolate the logic for creation and updating.
Here we have created a Django project and also set up a REST framework. This post will only be focusing on custom serializer fields.
Watch Video
In products/models.py
from django.db import models class ProductModel( models.Model ): product_id = models.AutoField(primary_key=True) name = models.CharField(max_length=255) featured_image = models.CharField(max_length=255, null=True) price = models.FloatField() class Meta: db_table = 'products' ordering = ( '-product_id', )
The ProductModel
is will just be used as an example.
Creating a custom serializer field using SerializerMethodField()
The SerializerMethodField
is a simple way of creating a custom field in the serializer class.
from rest_framework import serializers class ProductSerializer(serializers.Serializer): product = serializers.SerializerMethodField( ) // manipulates product field def get_product( self, obj ): name = ProductModel.objects.get(pk=obj['product']) return obj.name
If you are using SerializerMethodField()
then you must also provide a custom method to handle the manipulation of the field product
. And for that simple use, the field name prefixed by get_[fieldname]
.
Example: get_product
.
The serializer class will automatically call the get_product
when .data
property is called.
Caution
You will receive Attribute Error: ‘ProductSerializer’ object has no attribute ‘get_product’ if you don’t specify a method to a custom field.
Creating a Custom Serializer Field Class using serializers.Field
Django REST framework provides you the flexibility to create your own fully customized field class by inheriting serializers.Field
.
Import file from rest_framework import serializers
and use class serializers.Field
.
Creating Custom Field Class
In products/serializer_fields.py
from rest_framework import serializers from products.models import ProductModel class ProductSerializerField( serializers.Field ): # respresentation for json def to_representation(self, values): if isinstance( values['product'], ( ProductModel, ) ): values['product'] = values['product'].pk return values['product'] # respresentation for python object def to_internal_value(self, id): return ProductModel.objects.get(pk=id)
Note
- to_representation(self, values) : This will receive the values as python objects and return simplified primitive datatype to be represented as JSON.
The parametervalues
return a dictionary which contains the data passed to the field is thesource="*"
and if thesource="key_name"
then only that particular value is passed. - to_internal_value(self, id): This will receive the data for that particular field and will convert the primitive datatype to a python object. Which can be used for saving data in save or creating a method of the serializer.
Caution
If you set
source='*'
then you must pass a dictionary with the key as the name of the field or else you may get an exception as the object is not iterable.
In products/serializers.py
from products.serializer_fields import ProductSerializerField from rest_framework import routers, serializers, viewsets from products.models import ProductModel class ProductSerializer(serializers.Serializer): product = ProductSerializerField( source='*' ) def save( self, **kwargs ): return {} # you can save and return saved object instance
The source parameter refers to the attribute that needs to be assigned to the field.
data = { 'product' : { 'id' : 1 } } class ProductSerializer(serializers.Serializer): product = ProductSerializerField( source='*' ) #OR product = ProductSerializerField( source='product.id' )
If you pass source='*'
then it will pass complete dictionary in to_representation
method in the ProductSerializerField
.
HiddenField to exclude data from returning
This field will not be included during JSON parsing and will only be used within the serializer.
password = serializers.HiddenField( default='na' )
Conclusion
Creating a custom field in the serializer can be a very useful functionality. If you like this post then share it with your dev friends to import their knowledge on Django RestFramework.