Короткий ответ
Для межполевой валидации используют метод validate(self, attrs) сериализатора, который получает уже провалидированные по отдельности поля и может выбросить ValidationError, сославшись на конкретное поле или на сериализатор целиком.
Как это работает подробнее
DRF сначала прогоняет валидацию каждого поля отдельно (validate_<field_name> или встроенные валидаторы), и только если все поля по отдельности валидны, вызывает общий validate(attrs) с итоговым словарём. Там удобно сравнивать несколько полей между собой.
Пример кода
example.py
from rest_framework import serializers
class BookingSerializer(serializers.Serializer):
start_date = serializers.DateField()
end_date = serializers.DateField()
def validate(self, attrs):
if attrs["end_date"] < attrs["start_date"]:
raise serializers.ValidationError(
{"end_date": "Дата окончания не может быть раньше даты начала."}
)
return attrs
# Входные данные {"start_date": "2024-05-10", "end_date": "2024-05-01"}
# -> 400 с ошибкой в поле end_dateЧто использовать на практике
- Практика. Для вложенных объектов (например,
OrderItemSerializerвнутриOrderSerializer) используютmany=Trueи переопределяютcreate/update, так как DRF по умолчанию не умеет автоматически сохранять вложенные записи в связанные таблицы.
Подводные камни
- Риск. Пытаются сравнивать поля в
validate_start_date, где второе поле (end_date) ещё не гарантированно присутствует/провалидировано на этом этапе; не переопределяютcreate()для вложенных сериализаторов и получаютNotImplementedErrorпри попытке сохранить вложенные данные.