💻 Примеры: паттерны сериализаторов DRF
⚡ Ключевые паттерны
# Read + Write пара для Product
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
supplier = SupplierSerializer(read_only=True)
class Meta:
model = Product
fields = '__all__'
class ProductCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__' # category, supplier = ID
# read_only_fields
class OrderSerializer(serializers.ModelSerializer):
customer = CustomerSerializer(read_only=True)
class Meta:
model = Order
fields = '__all__'
read_only_fields = ['order_date']
# Валидация
def validate_quantity(self, value):
if value > 1000:
raise serializers.ValidationError('Не более 1000')
return value
Пример 1: Базовый CRUD-сериализатор
Простейший случай — когда модель не имеет связей или они не нужны во вложенном виде:
# store/serializers.py
from rest_framework import serializers
from .models import Category, Supplier, Address
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
class SupplierSerializer(serializers.ModelSerializer):
class Meta:
model = Supplier
fields = '__all__'
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = '__all__'
Такие сериализаторы работают для всех операций: GET, POST, PUT, PATCH, DELETE.
Пример 2: Read/Write пара для Product
from rest_framework import serializers
from .models import Product, Category, Supplier
# Для GET — возвращает вложенные объекты
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
supplier = SupplierSerializer(read_only=True)
class Meta:
model = Product
fields = '__all__'
# Для POST/PUT/PATCH — принимает category_id, supplier_id
class ProductCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
Как DRF принимает FK: Когда в
ProductCreateUpdateSerializer поле category не переопределено, DRF автоматически создаёт PrimaryKeyRelatedField — принимает числовой ID категории.
Пример 3: read_only_fields — защита служебных полей
from rest_framework import serializers
from .models import Order, Customer
class OrderSerializer(serializers.ModelSerializer):
customer = CustomerSerializer(read_only=True)
class Meta:
model = Order
fields = '__all__'
read_only_fields = ['order_date']
# order_date устанавливается автоматически (auto_now_add=True)
# и не должна меняться через API
Пример 4: Кастомная валидация телефона
import re
from rest_framework import serializers
from .models import Customer
class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['first_name', 'last_name', 'email', 'phone_number', 'address']
def validate_phone_number(self, value):
"""Номер телефона: 10-15 цифр, без спецсимволов."""
if not re.match(r'^\d{10,15}$', value):
raise serializers.ValidationError(
'Номер телефона должен содержать от 10 до 15 цифр.'
)
return value
Метод validate_phone_number вызывается автоматически, когда DRF обрабатывает поле phone_number. При ошибке — 400 Bad Request с сообщением.
Пример 5: Валидация числового поля quantity
from rest_framework import serializers
from .models import OrderItem
class OrderItemCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = '__all__'
def validate_quantity(self, value):
"""Количество не может превышать 1000."""
if value > 1000:
raise serializers.ValidationError(
'Количество товара должно быть не больше тысячи.'
)
return value
Пример 6: Вложенность нескольких уровней
Сериализатор OrderItemSerializer включает вложенные ProductSerializer и OrderSerializer, каждый из которых в свою очередь включает свои вложенные объекты:
class OrderItemSerializer(serializers.ModelSerializer):
product = ProductSerializer(read_only=True) # nested: Product -> Category, Supplier
order = OrderSerializer(read_only=True) # nested: Order -> Customer -> Address
class Meta:
model = OrderItem
fields = '__all__'
Производительность: Глубокая вложенность вызывает N+1 запросов. В реальных проектах используйте
select_related() и prefetch_related() в QuerySet view'а. Для практикума — допустимо.
Пример 7: Использование сериализаторов во view
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Product
from .serializers import ProductSerializer, ProductCreateUpdateSerializer
class ProductAPIView(APIView):
def get(self, request):
products = Product.objects.select_related('category', 'supplier').all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
def post(self, request):
serializer = ProductCreateUpdateSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)