🐛 Типичные ошибки: сериализаторы DRF

⚡ Топ-6 ошибок

  1. Нет read_only=True у nested-сериализатора → POST падает с ошибкой валидации
  2. Нет read_only_fields → клиент может изменить date_joined
  3. Нет import reNameError: name 're' is not defined
  4. Один сериализатор вместо двух → или вложенность ломает POST, или нет деталей в GET
  5. Орфографическая ошибка в validate_field_name → метод не вызывается
  6. Неверный regex → телефон принимается/отвергается неправильно

Ошибка 1: Нет read_only=True у вложенного сериализатора

Неверно

class ProductSerializer(serializers.ModelSerializer):
    # Нет read_only=True!
    category = CategorySerializer()

    class Meta:
        model = Product
        fields = '__all__'

Верно

class ProductSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)

    class Meta:
        model = Product
        fields = '__all__'

Симптом: При POST /api/products/ с телом {"category": 3} получаем 400 Bad Request: «This field is required» или «Invalid data. Expected a dictionary, but got int.»

Причина: Без read_only=True DRF ожидает полный вложенный объект при записи, а не числовой ID.

Ошибка 2: Не указан read_only_fields — клиент меняет служебные поля

Неверно

class CustomerSerializer(serializers.ModelSerializer):
    address = AddressSerializer(read_only=True)

    class Meta:
        model = Customer
        fields = '__all__'
        # Нет read_only_fields!

Верно

class CustomerSerializer(serializers.ModelSerializer):
    address = AddressSerializer(read_only=True)

    class Meta:
        model = Customer
        fields = '__all__'
        read_only_fields = [
            'date_joined', 'deleted', 'deleted_at'
        ]

Симптом: Клиент может через API установить deleted=true или изменить date_joined.

Ошибка 3: Забыт import re

Неверно

# Нет import re в начале файла!
from rest_framework import serializers
from .models import Customer

class CustomerCreateUpdateSerializer(...):
    ...
    def validate_phone_number(self, value):
        if not re.match(r'^\d{10,15}$', value):
            ...

Верно

from rest_framework import serializers
from .models import Customer
import re  # обязательно!

class CustomerCreateUpdateSerializer(...):
    ...
    def validate_phone_number(self, value):
        if not re.match(r'^\d{10,15}$', value):
            ...

Симптом: NameError: name 're' is not defined при первой попытке валидации.

Ошибка 4: Один сериализатор вместо двух

Попытка сделать один «универсальный» сериализатор с вложенными объектами для всех операций:

# Проблема: при POST нужно передавать полный JSON-объект Category
class ProductSerializer(serializers.ModelSerializer):
    category = CategorySerializer()  # работает для GET
    class Meta:
        model = Product
        fields = '__all__'
# При POST: {"category": {"name": "Электроника"}} — неудобно и опасно

Решение: Два сериализатора — ProductSerializer (read) и ProductCreateUpdateSerializer (write). Во view выбирать нужный.

Ошибка 5: Опечатка в имени метода validate_

Неверно

# Опечатка: phone_Number вместо phone_number
def validate_phone_Number(self, value):
    if not re.match(r'^\d{10,15}$', value):
        raise serializers.ValidationError('...')
    return value

Верно

# Регистр должен совпадать с именем поля модели
def validate_phone_number(self, value):
    if not re.match(r'^\d{10,15}$', value):
        raise serializers.ValidationError('...')
    return value

Симптом: Нет ошибки, но невалидные данные проходят — метод никогда не вызывается. DRF ищет метод по точному имени поля.

Ошибка 6: Неверный regex для телефона

Неверно

# Допускает любые символы, только проверяет длину
def validate_phone_number(self, value):
    if not re.match(r'^.{10,15}$', value):
        raise serializers.ValidationError('...')

Верно

# Только цифры, 10-15 символов
def validate_phone_number(self, value):
    if not re.match(r'^\d{10,15}$', value):
        raise serializers.ValidationError('...')

Разбор regex: ^ — начало строки, \d — только цифры 0-9, {10,15} — от 10 до 15 вхождений, $ — конец строки.

Ошибка 7: validate_quantity не возвращает value

Неверно

def validate_quantity(self, value):
    if value > 1000:
        raise serializers.ValidationError('...')
    # Нет return value!

Верно

def validate_quantity(self, value):
    if value > 1000:
        raise serializers.ValidationError('...')
    return value  # обязательно!

Симптом: Поле всегда получает значение None после валидации, что вызывает ошибку при сохранении в БД.

← К оглавлению урока    ← Решения    Ресурсы →