DEV Community

Cover image for Introduction to serializers in Django Rest Framework (DRF) Part 1
Prabodh Tuladhar
Prabodh Tuladhar

Posted on

Introduction to serializers in Django Rest Framework (DRF) Part 1

If you are new to Django REST Framework (DRF), one concept that often confuses beginners is Serializers.

In this article, I’ll break it down in simple terms, show you how to build one from scratch, and explain why they are the most critical part of your API.

What is a Serializer?

In DRF, a serializer is like a bridge between your database and the internet.

Django models store data as Python objects. However, when you want to send that data to a frontend application (like React or a mobile app), you cannot send Python objects. You need to send a format that everyone understands which is usually JSON.

Serializers perform three main jobs:

  1. Serialization: Converting complex Python objects (Models) into Python dictionaries (which can be easily rendered into JSON).
  2. Deserialization: Converting JSON data coming from a user back into complex Python objects.
  3. Validation: Checking if the incoming data is correct before saving it to the database.

Serialization and Deserialization

Why Do We Need Them?

In a standard Django application, we interact with data using Models. Let's look at a simple scenario. We want to build a store, so we define a ProductModel.

(Create this in your models.py file)

# demo/models.py

from django.db import models

class ProductModel(models.Model):
    name = models.CharField(max_length=150)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.IntegerField()
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name
Enter fullscreen mode Exit fullscreen mode

If you try to send a ProductModel instance directly to a web browser, it will crash. The browser doesn't speak "Python Class"; it speaks "JSON".

We need a translator. That translator is the Serializer.

Creating Your First Serializer

There are several types of serializers in DRF, such as ModelSerializer, HyperLinkedSerializer, and ListSerializer. To truly understand how they work, we are going to start with the base Serializer class.

We will create a serializers.py file in our app (let's call the app demo) and define a serializer that mirrors our model.

# demo/serializers.py
from rest_framework import serializers 

class ProductSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=150)
    description = serializers.CharField()
    price = serializers.DecimalField(max_digits=10, decimal_places=2)
    stock = serializers.IntegerField()
    is_active = serializers.BooleanField()
Enter fullscreen mode Exit fullscreen mode

Notice that we had to repeat the fields from the Model. We will solve this redundancy in Part 2, but for now, this explicit style helps us understand exactly what is happening.

Seeing Serialization in Action

The best way to learn DRF is not through the web browser, but through the Python Shell. This allows us to see the data transformation step-by-step.

Open your terminal and run. Make sure your python virtual environment where you have installed Django and Django Rest Framework is active.

python manage.py shell
Enter fullscreen mode Exit fullscreen mode

First, let's import our model and serializer.

from demo.models import ProductModel
from demo.serializers import ProductSerializer
Enter fullscreen mode Exit fullscreen mode

Step 1: Create Dummy Data

Let's create a product in our database using standard Django code.

product = ProductModel.objects.create(
    name='Logitech MX Master',
    description='Ergonomic Logitech Mouse', 
    price=110.99, 
    stock=72, 
    is_active=True
)
Enter fullscreen mode Exit fullscreen mode

Step 2: Serialize the Data

Now, we pass this product object into our serializer.

serializer = ProductSerializer(product)
Enter fullscreen mode Exit fullscreen mode

To see the translated data, we access the .data attribute.

print(serializer.data)
Enter fullscreen mode Exit fullscreen mode

Output:

{
   'name': 'Logitech MX Master',
   'description': 'Ergonomic Logitech Mouse',
   'price': '110.99',
   'stock': 72,
   'is_active': True
}
Enter fullscreen mode Exit fullscreen mode

Success! The serializer took a Python Object and converted it into a Python Dictionary. This dictionary can now be easily turned into JSON and sent over the API.

Deserialization (The Reverse Process)

Now, let's look at the reverse scenario. A user wants to create a new product via your API. They will send you a JSON object.

Let's assume this is the incoming data:

data = {
    "name": "Mechanical Keyboard",
    "description": "Backlit mechanical keyboard",
    "price": "24.99",
    "stock": 10,
    "is_active": True
}
Enter fullscreen mode Exit fullscreen mode

To convert this raw data back into a Python object, we pass it to the serializer using the data argument:

serializer = ProductSerializer(data=data)
Enter fullscreen mode Exit fullscreen mode

A common mistake beginners make is trying to access the data immediately.

# DO NOT DO THIS
print(serializer.data)
Enter fullscreen mode Exit fullscreen mode

Output:

AssertionError: When a serializer is passed a `data` keyword argument you must call `.is_valid()` before attempting to access the serialized `.data` representation.
Enter fullscreen mode Exit fullscreen mode

DRF protects your database. It refuses to let you touch the data until you confirm it is valid. You must call is_valid() first. If the is_valid() method is not called, Python will throw an AssertionError

if serializer.is_valid():
    print(serializer.validated_data)
else:
    print(serializer.errors)
Enter fullscreen mode Exit fullscreen mode

Since our data matches the requirements (e.g., price is a decimal, stock is an integer, is_active is boolean), it returns True.

Saving the Data

Now that the data is valid, we want to save it to the database. Usually, you would call serializer.save().

However, if you try to run serializer.save() right now, it will fail.

Why? Because the base Serializer class doesn't know how to create a ProductModel. We have to tell it how.

Let's go back to serializers.py and implement the create() method.

class ProductSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=150)
    description = serializers.CharField()
    price = serializers.DecimalField(max_digits=10, decimal_places=2)
    stock = serializers.IntegerField()
    is_active = serializers.BooleanField()

    # We must implement this to support saving data
    def create(self, validated_data):
        # We unpack the validated data and create a model instance
        return ProductModel.objects.create(**validated_data)
Enter fullscreen mode Exit fullscreen mode

Now, back in your shell, if you run:

serializer.save()
Enter fullscreen mode Exit fullscreen mode

It will successfully create the "Mechanical Keyboard" in your database.

Wrap Up

We have successfully built a serializer that can:

  1. Read a Django Model and convert it to a dictionary (Read).
  2. Take a dictionary, validate it, and convert it into a Django Model (Write).

But did you notice something annoying?

We repeated a lot of code. We typed name, price, and stock in the Model, and then we typed them again in the Serializer. In a real project with dozens of models, this violates the DRY (Don't Repeat Yourself) principle.

In Part 2, I will introduce the ModelSerializer, a powerful shortcut that writes all this boilerplate code for you automatically.


References

  1. Serializers - Django Rest Framework
  2. Serialization Tutorial - Django Rest Framework

Top comments (0)