Search Here

How to Create Custom Serializer Fields in Django REST Framework

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.

Also read our popular post on Django Signals

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

You need to provide two methods they are:
  • to_representation(self, values) : This will receive the values as python objects and return simplified primitive datatype to be represented as JSON.
    The parameter values return a dictionary which contains the data passed to the field is the source="*" and if the source="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.

You can learn more about Serializer Fields by visiting Django REST Framework Serializer Field.

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.