Официальная оригинальная ссылка
Эта серия статей адрес github
Пожалуйста, укажите источник
валидатор
В большинстве случаев, когда вы имеете дело с проверкой в среде REST, вы просто полагаетесь на проверку поля по умолчанию или пишете явные методы проверки для сериализации или классов полей.
Однако иногда вам может понадобиться поместить логику проверки в повторно используемый компонент, чтобы его можно было легко повторно использовать в кодовой базе. Этого можно достичь с помощью функций проверки и классов проверки.
Проверка в среде REST
Проверка в сериализаторах Django REST framework с помощью DjangoModelForm
Валидация в классе работает немного по-другому.
использоватьModelForm
, проверка выполняется частично для формы и частично для экземпляра модели. В среде REST проверка выполняется полностью для сериализованного класса. Это выгодно по следующим причинам:
- Он правильно разделяет проблемы и делает поведение кода более понятным.
- Используйте быстрый
ModelSerializer
классы и использование явныхSerializer
Классы можно легко переключать. любой дляModelSerializer
Поведение проверки легко воспроизвести. - напечатать сериализованный экземпляр класса
repr
Будут отображены применяемые правила проверки. Для экземпляров модели нет дополнительного скрытого поведения проверки (поскольку все это относится к классам сериализации).
когда вы используетеModelSerializer
, все проверки выполняются автоматически. Если вы хотите вместо этого использоватьSerializer
class, вам нужно явно определить правила проверки.
взять каштан
В качестве примера того, как инфраструктура REST использует явную проверку, мы возьмем простой класс модели с полями, которые имеют уникальные ограничения.
class CustomerReportRecord(models.Model):
time_raised = models.DateTimeField(default=timezone.now, editable=False)
reference = models.CharField(unique=True, max_length=20)
description = models.TextField()
Ниже приведена основнаяModelSerializer
, мы можем использовать его для создания или обновленияCustomerReportRecord
Пример:
class CustomerReportSerializer(serializers.ModelSerializer):
class Meta:
model = CustomerReportRecord
использовать сейчасmanage.py shell
Откройте оболочку Джанго
>>> from project.example.serializers import CustomerReportSerializer
>>> serializer = CustomerReportSerializer()
>>> print(repr(serializer))
CustomerReportSerializer():
id = IntegerField(label='ID', read_only=True)
time_raised = DateTimeField(read_only=True)
reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>])
description = CharField(style={'type': 'textarea'})
Самое интересное здесьreference
поле. Мы видим, что ограничение уникальности явно применяется валидатором к сериализованному полю.
Из-за этого более явного стиля среда REST включает в себя некоторые классы валидаторов, которых нет в ядре Django. Эти классы подробно описаны ниже.
UniqueValidator
Этот валидатор можно использовать для принудительного применения полей модели.unique=True
ограничение. Он принимает один обязательный параметр и один необязательныйmessages
параметр:
-
queryset
должен- Это набор запросов для проверки уникальности. -
message
- Сообщение об ошибке для использования при сбое проверки. -
lookup
- Существующий экземпляр для поиска проверенного значения. По умолчанию'exact'
.
Этот валидатор следует применять к сериализованным полям, например:
from rest_framework.validators import UniqueValidator
slug = SlugField(
max_length=100,
validators=[UniqueValidator(queryset=BlogPost.objects.all())]
)
UniqueTogetherValidator
Этот валидатор можно использовать для принудительного применения экземпляров модели.unique_together
ограничение. Он имеет два обязательных параметра и один необязательный.messages
параметр:
-
queryset
должен- Это набор запросов для проверки уникальности. -
fields
должен- Список или кортеж имен полей, набор должен быть уникальным (это означает, что набор значений, представленных полями в наборе, не может появляться в двух частях данных одновременно). Все эти поля должны быть полями сериализованного класса. -
message
- Сообщение об ошибке для использования при сбое проверки.
Валидаторы должны применяться к классам сериализации следующим образом:
from rest_framework.validators import UniqueTogetherValidator
class ExampleSerializer(serializers.Serializer):
# ...
class Meta:
# ToDo items belong to a parent list, and have an ordering defined
# by the 'position' field. No two items in a given list may share
# the same position.
validators = [
UniqueTogetherValidator(
queryset=ToDoItem.objects.all(),
fields=('list', 'position')
)
]
Уведомление: UniqueTogetherValidation
Класс всегда накладывает неявное ограничение на то, что все поля, к которым он применяется, обрабатываются по запросу. имеютdefault
Поля значений являются исключением, так как они всегда содержат значение, даже если это значение отсутствует при вводе пользователем.
UniqueForDateValidator
UniqueForMonthValidator
UniqueForYearValidator
Эти валидаторы могут использоваться для обеспеченияunique_for_date
,unique_for_month
иunique_for_year
ограничение. Они имеют следующие параметры:
-
queryset
должен- Это набор запросов для проверки уникальности. -
field
должен- Имя поля, которое необходимо проверить на уникальность в заданном диапазоне дат. Поле должно быть полем сериализованного класса. -
date_field
должен- Имя поля диапазона дат, которое будет использоваться для определения ограничения уникальности. Поле должно быть полем сериализованного класса. -
message
- Сообщение об ошибке для использования при сбое проверки.
Валидаторы должны применяться к классам сериализации следующим образом:
from rest_framework.validators import UniqueForYearValidator
class ExampleSerializer(serializers.Serializer):
# ...
class Meta:
# Blog posts should have a slug that is unique for the current year.
validators = [
UniqueForYearValidator(
queryset=BlogPostItem.objects.all(),
field='slug',
date_field='published'
)
]
Позвольте мне объяснить, приведенный выше пример означает, что в
published
год, на который приходится дата,slug
Значение поля должно быть уникальным, обратите внимание, неpublished
Точно равные даты, но равные годы.unique_for_date
,unique_for_month
То же самое справедливо.
Поле даты, используемое для проверки, всегда должно присутствовать в классе сериализации. Вы не можете просто полагаться на классы моделейdefault=...
, так как значение по умолчанию не создается до тех пор, пока не будет запущена проверка.
Вам может понадобиться использовать несколько стилей, в зависимости от того, как вы хотите, чтобы API выглядел. если вы используетеModelSerializer
, вероятно, просто полагайтесь на значения по умолчанию, которые генерирует для вас инфраструктура REST, но если вы используетеSerializer
Или для более явного контроля используйте стили, показанные ниже.
Используется с записываемыми полями даты.
Если вы хотите, чтобы поле даты было доступно для записи, единственное, что стоит отметить, это то, что вы должны убедиться, что оно всегда доступно во входных данных, что можно сделать, установивdefault
параметр или настройкаrequired=True
реализовать.
published = serializers.DateTimeField(required=True)
Используется с полями даты, доступными только для чтения.
Если вы хотите, чтобы поле даты было видно, но не редактировалось пользователем, установитеread_only=True
и дополнительно установитьdefault=...
параметр.
published = serializers.DateTimeField(read_only=True, default=timezone.now)
Поле недоступно для записи пользователем, но значение по умолчанию все равно будет передано вvalidated_data
.
Используется со скрытыми полями даты.
Если вы хотите, чтобы поле даты было полностью скрыто от пользователя, используйтеHiddenField
. Тип поля не принимает пользовательский ввод, но всегда возвращает значение по умолчанию сериализованному классу.validated_data
.
published = serializers.HiddenField(default=timezone.now)
Уведомление: UniqueFor<Range>Validation
Класс всегда накладывает неявное ограничение на то, что все поля, к которым он применяется, обрабатываются по запросу. имеютdefault
Поля значений являются исключением, так как они всегда содержат значение, даже если это значение отсутствует при вводе пользователем.
Advanced field defaults
Валидатор, применяемый в нескольких полях сериализованного класса, иногда не требует ввода поля, предоставляемого клиентом API, но его можно использовать в качестве входных данных для валидатора.
Существует два режима, в которых может потребоваться эта проверка:
- использовать
HiddenField
. Поле появится вvalidated_data
, но не в сериализованном выходном представлении. - использовать
read_only=True
Стандартные поля , но также содержатdefault=...
параметр. Это поле будет использоваться в сериализованном представлении вывода, но не может быть задано пользователем напрямую.
Платформа REST включает некоторые значения по умолчанию, которые могут быть полезны в этой ситуации.
CurrentUserDefault
Класс по умолчанию, который можно использовать для представления текущего пользователя. Чтобы использовать его, при создании экземпляра сериализованного класса'request'
Должен быть предоставлен как часть контекстного словаря.
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
CreateOnlyDefault
Класс по умолчанию, который можно использовать для установки только параметров по умолчанию во время операции создания. Во время обновления это поле опускается.
Он принимает один параметр, который является параметром по умолчанию или вызываемым параметром, который следует использовать во время операции создания.
created_at = serializers.DateTimeField(
read_only=True,
default=serializers.CreateOnlyDefault(timezone.now)
)
Ограничения валидатора
Есть некоторые неоднозначные случаи, когда вам нужно явно обрабатывать проверку вместо того, чтобы полагаться наModelSerializer
Сгенерированный класс сериализации по умолчанию.
В этих случаях вы можете захотеть сериализовать класс с помощьюMeta.validators
Свойство указывает пустой список для отключения автоматически сгенерированных валидаторов.
необязательные поля
По умолчанию проверка «уникально вместе» заставляет все поля бытьrequired=True
. В некоторых случаях может потребоваться явно указатьrequired=False
Применяется к одному из полей, и в этом случае желаемое поведение для проверки неоднозначно.
В этом случае обычно нужно исключить валидатор из класса сериализации, а в.validate()
Напишите логику проверки явно в методе или в представлении.
Например:
class BillingRecordSerializer(serializers.ModelSerializer):
def validate(self, data):
# Apply custom validation either here, or in the view.
class Meta:
fields = ('client', 'date', 'amount')
extra_kwargs = {'client': {'required': 'False'}}
validators = [] # Remove a default "unique together" constraint.
Обновление вложенных классов сериализации
При применении обновления к существующему экземпляру валидатор уникальности исключает текущий экземпляр из проверки уникальности. Текущий экземпляр доступен в контексте проверки уникальности, поскольку он существует как атрибут в сериализаторе, который изначально использовался при создании экземпляра сериализованного класса.instance=...
перечислить.
Это исключение нельзя применить, когда операция обновления выполняется для вложенного сериализованного класса, поскольку экземпляр недоступен.
Еще раз вам может понадобиться явно удалить валидатор из класса сериализации и явно написать код, который проверяет ограничения..validate()
метод или представление.
Отладка сложных случаев
если вы не увереныModelSerializer
поведение класса по умолчанию, затем запускmanage.py shell
И обычно рекомендуется распечатать сериализованный экземпляр класса, чтобы вы могли проверить его автоматически сгенерированные поля и валидаторы.
>>> serializer = MyComplexModelSerializer()
>>> print(serializer)
class MyComplexModelSerializer:
my_fields = ...
Также имейте в виду, что в сложных случаях часто лучше явно определить класс сериализации, чем полагаться на класс по умолчанию.ModelSerializer
поведение. Хотя это потребует написания большего количества кода, это гарантирует, что окончательное поведение будет более прозрачным.
Написание пользовательских валидаторов
Вы можете использовать существующие валидаторы Django или написать собственные.
функция на основе
Валидатор может быть любым вызываемым, вызываемым при сбоеserializers.ValidationError
.
def even_number(value):
if value % 2 != 0:
raise serializers.ValidationError('This field must be an even number.')
Проверка на уровне поля
ты можешь пройтиSerializer
добавить подкласс.validate_<field_name>
метод для указания пользовательской проверки на уровне поля.
основанный на классе
Чтобы написать валидатор на основе классов, используйте__call__
метод. Валидаторы на основе классов полезны, потому что они позволяют параметризовать и повторно использовать поведение.
class MultipleOf(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value % self.base != 0:
message = 'This field must be a multiple of %d.' % self.base
raise serializers.ValidationError(message)
использоватьset_context()
В некоторых сложных случаях вы можете захотеть проверить сериализованное поле в валидаторе. На данный момент вы можете сделать это, объявив валидатор на основе классовset_context
способ сделать это.
def set_context(self, serializer_field):
# Determine if this is an update or a create operation.
# In `__call__` we can then use that information to modify the validation behavior.
self.is_update = serializer_field.parent.instance is not None