Django REST Framework Serializers

Converting data between complex types and JSON

🔄 What are Serializers?

Serializers convert complex data types like Django models into JSON format and vice versa. They handle validation, data transformation, and provide a clean way to represent your data in APIs.


# Basic serializer example
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    author = serializers.CharField(max_length=100)
    published_date = serializers.DateField()
                                    

Output:

{
    "title": "Python Guide",
    "author": "John Doe",
    "published_date": "2024-01-15"
}

Serializer Types

📝

Serializer

Basic serializer class

class BookSerializer(Serializer):
    title = CharField()
    author = CharField()
🗄️

ModelSerializer

Auto-generate from models

class BookSerializer(ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
🔗

Nested Serializers

Handle related objects

class BookSerializer(ModelSerializer):
    author = AuthorSerializer()
    class Meta:
        model = Book

Validation

Built-in data validation

def validate_title(self, value):
    if len(value) < 3:
        raise ValidationError("Too short")
    return value

🔹 Basic Serializer

Create a simple serializer by defining fields manually. This gives you full control over data representation and validation rules:

# serializers.py
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=200)
    author = serializers.CharField(max_length=100)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    is_available = serializers.BooleanField(default=True)
    
    def create(self, validated_data):
        return Book.objects.create(**validated_data)
    
    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.author = validated_data.get('author', instance.author)
        instance.save()
        return instance

🔹 ModelSerializer

ModelSerializer automatically generates fields from your Django model, reducing code duplication and ensuring consistency between your model and API:

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    published_date = models.DateField()
    
    def __str__(self):
        return self.title
# serializers.py
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'  # Include all fields
        # Or specify fields: fields = ['id', 'title', 'author']
        # Or exclude fields: exclude = ['created_at']

Output:

{
    "id": 1,
    "title": "Django for Beginners",
    "author": "William Vincent",
    "price": "39.99",
    "published_date": "2024-01-15"
}

🔹 Using Serializers in Views

Integrate serializers with views to handle data conversion and validation automatically:

# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer

@api_view(['GET', 'POST'])
def book_list(request):
    if request.method == 'GET':
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)
    
    elif request.method == 'POST':
        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)

🔹 Field Options

Customize serializer fields with various options to control behavior:

class BookSerializer(serializers.ModelSerializer):
    # Read-only field (won't accept input)
    id = serializers.IntegerField(read_only=True)
    
    # Write-only field (won't appear in output)
    password = serializers.CharField(write_only=True)
    
    # Required field
    title = serializers.CharField(required=True)
    
    # Optional field with default
    is_published = serializers.BooleanField(default=False)
    
    # Custom source (different field name in model)
    book_title = serializers.CharField(source='title')
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'book_title', 'is_published']

🔹 Custom Validation

Add custom validation logic to ensure data integrity before saving:

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
    
    # Field-level validation
    def validate_title(self, value):
        if len(value) < 3:
            raise serializers.ValidationError("Title must be at least 3 characters")
        return value
    
    # Object-level validation
    def validate(self, data):
        if data['price'] < 0:
            raise serializers.ValidationError("Price cannot be negative")
        if data['published_date'] > date.today():
            raise serializers.ValidationError("Cannot publish in future")
        return data

Validation Error Output:

{
    "title": ["Title must be at least 3 characters"],
    "non_field_errors": ["Price cannot be negative"]
}

🔹 Nested Serializers

Handle related objects by nesting serializers for complex data structures:

# models.py
class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

# serializers.py
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ['id', 'name', 'email']

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

Output:

{
    "id": 1,
    "title": "Python Mastery",
    "author": {
        "id": 1,
        "name": "John Doe",
        "email": "[email protected]"
    }
}

🧠 Test Your Knowledge

Which serializer automatically generates fields from a Django model?