Руководство по API платформы Django REST (12): Аутентификаторы

задняя часть Python Django

Официальная оригинальная ссылка
Эта серия статей адрес github
Пожалуйста, укажите источник

валидатор

В большинстве случаев, когда вы имеете дело с проверкой в ​​среде REST, вы просто полагаетесь на проверку поля по умолчанию или пишете явные методы проверки для сериализации или классов полей.

Однако иногда вам может понадобиться поместить логику проверки в повторно используемый компонент, чтобы его можно было легко повторно использовать в кодовой базе. Этого можно достичь с помощью функций проверки и классов проверки.

Проверка в среде REST

Проверка в сериализаторах Django REST framework с помощью DjangoModelFormВалидация в классе работает немного по-другому.

использоватьModelForm, проверка выполняется частично для формы и частично для экземпляра модели. В среде REST проверка выполняется полностью для сериализованного класса. Это выгодно по следующим причинам:

  • Он правильно разделяет проблемы и делает поведение кода более понятным.
  • Используйте быстрыйModelSerializerклассы и использование явныхSerializerКлассы можно легко переключать. любой дляModelSerializerПоведение проверки легко воспроизвести.
  • напечатать сериализованный экземпляр классаreprБудут отображены применяемые правила проверки. Для экземпляров модели нет дополнительного скрытого поведения проверки (поскольку все это относится к классам сериализации).

когда вы используетеModelSerializer, все проверки выполняются автоматически. Если вы хотите вместо этого использоватьSerializerclass, вам нужно явно определить правила проверки.

взять каштан

В качестве примера того, как инфраструктура 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