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]"
}
}