Валидаторы
источник: - validators.py
Валидаторы
Валидаторы могут быть полезны для повторного использования логики проверки между различными типами полей.
В большинстве случаев, когда вы имеете дело с проверкой в DRF, вы просто полагаетесь на стандартную проверку полей, либо пишете явные методы проверки в сериализаторе или классах полей.
Однако иногда вам захочется поместить логику валидации в компоненты многократного использования, чтобы ее можно было легко повторно использовать в кодовой базе. Этого можно достичь с помощью функций валидатора и классов валидатора.
Валидация в DRF
Валидация в сериализаторах DRF обрабатывается немного иначе, чем валидация в классе Django ModelForm
.
При использовании ModelForm
валидация выполняется частично на форме, частично на экземпляре модели. При использовании DRF валидация выполняется полностью на классе сериализатора. Это выгодно по следующим причинам:
Обеспечивается правильное разделение обязанностей, что делает поведение вашего кода более очевидным.
Легко переключаться между использованием коротких классов
ModelSerializer
и явными классамиSerializer
. Любое поведение проверки, используемое дляModelSerializer
, легко повторить.Распечатка
repr
экземпляра сериализатора покажет вам, какие именно правила проверки он применяет. Нет никакого дополнительного скрытого поведения проверки, вызываемого на экземпляре модели.
При использовании ModelSerializer
все это обрабатывается автоматически. Если вы хотите перейти к использованию классов Serializer
, то вам необходимо явно определить правила валидации.
Пример
В качестве примера того, как DRF использует явную валидацию, возьмем простой класс модели, в котором есть поле с ограничением уникальности.
Вот базовый ModelSerializer
, который мы можем использовать для создания или обновления экземпляров CustomerReportRecord
:
Если мы откроем оболочку Django с помощью manage.py shell
, то теперь мы можем
Интересным здесь является поле reference
. Мы видим, что ограничение уникальности явно обеспечивается валидатором на поле сериализатора.
Из-за этого более явного стиля DRF включает несколько классов валидаторов, которые отсутствуют в основном Django. Эти классы подробно описаны ниже. Валидаторы DRF, как и их аналоги в Django, реализуют метод __eq__
, позволяющий сравнивать экземпляры на равенство.
UniqueValidator
Этот валидатор может быть использован для обеспечения ограничения unique=True
на поля модели. Он принимает один обязательный аргумент и необязательный аргумент messages
:
queryset
обязательно - Это набор запросов, в отношении которого должна быть обеспечена уникальность.message
- Сообщение об ошибке, которое должно быть использовано при неудачной проверке.lookup
- Поиск, используемый для нахождения существующего экземпляра с проверяемым значением. По умолчанию'exact'
.
Этот валидатор должен применяться к полям сериализатора, например, так:
UniqueTogetherValidator
Этот валидатор можно использовать для наложения ограничений unique_together
на экземпляры моделей. Он имеет два обязательных аргумента и один необязательный аргумент messages
:
queryset
обязательно - Это набор запросов, по которому должна быть обеспечена уникальность.fields
обязательно - Список или кортеж имен полей, которые должны составлять уникальный набор. Они должны существовать как поля в классе сериализатора.message
- Сообщение об ошибке, которое должно быть использовано при неудачной проверке.
Валидатор должен применяться к классам сериализатора, например, так:
Примечание: Класс UniqueTogetherValidator
всегда накладывает неявное ограничение на то, что все поля, к которым он применяется, всегда рассматриваются как обязательные. Поля со значениями default
являются исключением из этого правила, так как они всегда предоставляют значение, даже если оно опущено при вводе пользователем.
UniqueForDateValidator
UniqueForMonthValidator
UniqueForYearValidator
Эти валидаторы могут использоваться для наложения ограничений unique_for_date
, unique_for_month
и unique_for_year
на экземпляры модели. Они принимают следующие аргументы:
queryset
обязательно - Это набор запросов, по которым будет проверяться уникальность.field
обязательно - Имя поля, по которому будет проверяться уникальность в заданном диапазоне дат. Оно должно существовать как поле в классе сериализатора.date_field
обязательно - Имя поля, которое будет использоваться для определения диапазона дат для ограничения уникальности. Оно должно существовать как поле в классе сериализатора.message
- Сообщение об ошибке, которое должно быть использовано при неудачной проверке.
Валидатор должен применяться к классам сериализатора, например, так:
Поле даты, которое используется для проверки, всегда должно присутствовать в классе сериализатора. Вы не можете просто положиться на класс модели default=...
, потому что значение, используемое по умолчанию, будет сгенерировано только после выполнения валидации.
Есть несколько стилей, которые вы можете использовать для этого, в зависимости от того, как вы хотите, чтобы ваш API вел себя. Если вы используете ModelSerializer
, вы, вероятно, просто будете полагаться на значения по умолчанию, которые генерирует для вас DRF, но если вы используете Serializer
или просто хотите более явного контроля, используйте один из стилей, продемонстрированных ниже.
Использование с записываемым полем даты.
Если вы хотите, чтобы поле даты было доступно для записи, единственное, что стоит отметить, это то, что вы должны убедиться, что оно всегда доступно во входных данных, либо задав аргумент default
, либо установив required=True
.
Использование с полем даты, доступным только для чтения.
Если вы хотите, чтобы поле даты было видно, но не редактировалось пользователем, то установите read_only=True
и дополнительно задайте аргумент default=...
.
Использование со скрытым полем даты.
Если вы хотите, чтобы поле даты было полностью скрыто от пользователя, используйте HiddenField
. Этот тип поля не принимает пользовательский ввод, а вместо этого всегда возвращает значение по умолчанию в validated_data
в сериализаторе.
Примечание: Классы UniqueFor<Range>Validator
накладывают неявное ограничение на то, что поля, к которым они применяются, всегда рассматриваются как обязательные. Поля со значениями default
являются исключением из этого правила, так как они всегда предоставляют значение, даже если оно опущено при вводе пользователем.
Примечание: HiddenField()
не появляется в сериализаторе partial=True
(при выполнении запроса PATCH
). Это поведение может измениться в будущем, следите за обновлениями на github discussion.
Расширенные значения полей по умолчанию
Валидаторы, применяемые к нескольким полям в сериализаторе, иногда могут потребовать ввода поля, которое не должно предоставляться клиентом API, но которое доступно в качестве входных данных для валидатора. Для этих целей используйте HiddenField
. Это поле будет присутствовать в validated_data
, но не будет использоваться в выходном представлении сериализатора.
Примечание: Использование поля read_only=True
исключается из записываемых полей, поэтому оно не будет использовать аргумент default=...
. Смотрите 3.8 объявление.
DRF включает в себя несколько параметров по умолчанию, которые могут быть полезны в данном контексте.
CurrentUserDefault
Класс по умолчанию, который можно использовать для представления текущего пользователя. Чтобы использовать его, request
должен быть предоставлен как часть контекстного словаря при инстанцировании сериализатора.
CreateOnlyDefault
Класс по умолчанию, который можно использовать только для установки аргумента по умолчанию во время операций создания. При обновлении поле опускается.
Он принимает один аргумент, который является значением по умолчанию или вызываемым модулем, который должен использоваться при создании.
Ограничения валидаторов
Есть несколько неоднозначных случаев, когда вам придется явно обрабатывать валидацию, а не полагаться на классы сериализаторов по умолчанию, которые генерирует ModelSerializer
.
В таких случаях вы можете отключить автоматически сгенерированные валидаторы, указав пустой список для атрибута сериализатора Meta.validators
.
Необязательные поля
По умолчанию валидация unique_together
принудительно требует, чтобы все поля были required=True
. В некоторых случаях вы можете захотеть явно применить required=False
к одному из полей, и тогда желаемое поведение валидации будет неоднозначным.
В этом случае, как правило, необходимо исключить валидатор из класса сериализатора, а всю логику проверки написать явно либо в методе .validate()
, либо в представлении.
Например:
Обновление вложенных сериализаторов
При применении обновления к существующему экземпляру валидаторы уникальности исключают текущий экземпляр из проверки уникальности. Текущий экземпляр доступен в контексте проверки уникальности, поскольку он существует как атрибут сериализатора, будучи изначально переданным с помощью instance=...
при инстанцировании сериализатора.
В случае операций обновления для вложенных сериализаторов нет возможности применить это исключение, поскольку экземпляр недоступен.
Опять же, вероятно, вам захочется явно удалить валидатор из класса сериализатора и написать код для ограничения валидации явно, в методе .validate()
или в представлении.
Отладка сложных случаев
Если вы не уверены в том, какое именно поведение будет генерировать класс ModelSerializer
, обычно полезно запустить manage.py shell
и распечатать экземпляр сериализатора, чтобы вы могли проверить поля и валидаторы, которые он автоматически генерирует для вас.
Также имейте в виду, что в сложных случаях часто бывает лучше явно определить свои классы сериализатора, а не полагаться на поведение ModelSerializer
по умолчанию. Это потребует немного больше кода, но гарантирует, что результирующее поведение будет более прозрачным.
Написание пользовательских валидаторов
Вы можете использовать любой из существующих валидаторов Django или написать свой собственный валидатор.
Валидаторы, основанные на функциях
Валидатором может быть любой вызываемый объект, который при неудаче вызывает ошибку serializers.ValidationError
.
Валидация на уровне поля
Вы можете задать пользовательскую проверку на уровне полей, добавив методы .validate_<имя_поля>
в подкласс Serializer
. Это описано в документации по сериализаторам
На основе класса
Чтобы написать валидатор на основе класса, используйте метод __call__
. Валидаторы на основе классов полезны тем, что позволяют параметризировать и повторно использовать поведение.
Доступ к контексту
В некоторых сложных случаях вы можете захотеть, чтобы валидатору передавалось поле сериализатора, с которым он используется, в качестве дополнительного контекста. Вы можете сделать это, установив атрибут requires_context = True
для класса валидатора. Тогда метод __call__
будет вызван с полем serializer_field
или serializer
в качестве дополнительного аргумента.
Last updated