Serializers in Django

3 minute read

In layman terms, serializers in Django REST Framework (DRF) are like translators. They convert complex data like database records (e.g., Python objects) into simple, readable formats like JSON or XML that can be sent over an API. Similarly, they can convert incoming data (e.g., JSON) into Python objects that your application can work with.

Why Are Serializers Needed?

  1. For Output:
    • Imagine you have user data stored in your database. To send it via an API, you need to convert it into JSON format. Serializers handle this conversion.
  2. For Input:
    • If you receive JSON data from an API request (e.g., to create a new user), serializers validate the data and transform it into a format your app can use.

A Simple Example

Let’s say we are building an API for managing books.

Step 1: Define a Model

Here’s a simple model for a book:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    isbn = models.CharField(max_length=13, unique=True)

    def __str__(self):
        return self.title

Step 2: Create a Serializer

Create a serializer to translate the Book model into JSON and vice versa.

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'published_date', 'isbn']
  • ModelSerializer:
    • A shortcut for creating serializers for models.
    • Automatically handles most of the work, such as field mapping and validation.

Using the Serializer

Serialize a Model Instance (Convert to JSON)

from .models import Book
from .serializers import BookSerializer

# Example: Serialize a single book
book = Book.objects.create(
    title="The Great Gatsby",
    author="F. Scott Fitzgerald",
    published_date="1925-04-10",
    isbn="1234567890123"
)

serializer = BookSerializer(book)
print(serializer.data)

Output (JSON format):

{
    "id": 1,
    "title": "The Great Gatsby",
    "author": "F. Scott Fitzgerald",
    "published_date": "1925-04-10",
    "isbn": "1234567890123"
}

Serialize Multiple Model Instances

# Example: Serialize multiple books
books = Book.objects.bulk_create([
    Book(title="1984", author="George Orwell", published_date="1949-06-08", isbn="1234567890124"),
    Book(title="To Kill a Mockingbird", author="Harper Lee", published_date="1960-07-11", isbn="1234567890125")
])

serializer = BookSerializer(books, many=True)
print(serializer.data)

Output (JSON format):

[
    {
        "id": 2,
        "title": "1984",
        "author": "George Orwell",
        "published_date": "1949-06-08",
        "isbn": "1234567890124"
    },
    {
        "id": 3,
        "title": "To Kill a Mockingbird",
        "author": "Harper Lee",
        "published_date": "1960-07-11",
        "isbn": "1234567890125"
    }
]

Deserialize JSON Data (Convert to Python Object)

from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from io import BytesIO

# Example JSON data
book_json = '{"title": "1984", "author": "George Orwell", "published_date": "1949-06-08", "isbn": "9876543210123"}'

# Convert JSON to Python dictionary
book_data = JSONParser().parse(BytesIO(book_json.encode('utf-8')))
serializer = BookSerializer(data=book_data)

if serializer.is_valid():
    book = serializer.save()  # Create a new Book instance
    print(book)  # Output: Book object (1984 by George Orwell)
else:
    print(serializer.errors)

Advanced Serializer Features

1. Custom Validation

Add custom validation rules to ensure data integrity.

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'published_date', 'isbn']

    def validate_isbn(self, value):
        if len(value) != 13:
            raise serializers.ValidationError("ISBN must be 13 characters long.")
        return value

2. Non-Model Serializers

If you don’t need to work with a model, use a Serializer instead of a ModelSerializer.

class CustomBookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    author = serializers.CharField(max_length=100)

    def create(self, validated_data):
        # Handle custom object creation
        return Book.objects.create(**validated_data)

    def update(self, instance, validated_data):
        # Handle object updates
        instance.title = validated_data.get('title', instance.title)
        instance.author = validated_data.get('author', instance.author)
        instance.save()
        return instance

Integrating Serializers with Views

DRF views (e.g., APIView, ViewSets) use serializers to handle data input and output. Example View:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer

class BookListView(APIView):
    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Summary

  • Serializers handle data conversion and validation between models and JSON (or other formats).
  • ModelSerializer simplifies creating serializers for database models.
  • Validation ensures data integrity.
  • Serializers are integral to APIs for handling data input and output.

Leave a comment