🐛 Типичные ошибки: сериализаторы DRF
⚡ Топ-6 ошибок
- Нет
read_only=Trueу nested-сериализатора → POST падает с ошибкой валидации - Нет
read_only_fields→ клиент может изменитьdate_joined - Нет
import re→NameError: name 're' is not defined - Один сериализатор вместо двух → или вложенность ломает POST, или нет деталей в GET
- Орфографическая ошибка в
validate_field_name→ метод не вызывается - Неверный 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 после валидации, что вызывает ошибку при сохранении в БД.