Подтвердить что ты не робот

Порядок проверки Serializer в Django REST Framework

Ситуация

Во время работы с проверкой в ​​Django REST Framework ModelSerializer я заметил, что поля Meta.model всегда проверяются, даже если это не имеет смысла. Возьмем следующий пример для сериализации модели User:

  • У меня есть конечная точка, которая создает пользователя. Таким образом, поле password и поле confirm_password. Если два поля не совпадают, пользователь не может быть создан. Аналогично, если запрошенный username уже существует, пользователь не может быть создан.
  • Пользовательские POST-коды не соответствуют значениям для каждого из указанных выше полей.
  • В сериализаторе была реализована реализация validate (см. ниже), улавливая не совпадающие поля password и confirm_password

Реализация validate:

def validate(self, data):
    if data['password'] != data.pop('confirm_password'):
        raise serializers.ValidationError("Passwords do not match")
    return data

Проблема

Даже когда ValidationError поднят на validate, ModelSerializer по-прежнему запрашивает базу данных, чтобы проверить, используется ли username. Это видно в списке ошибок, который возвращается из конечной точки; присутствуют как модельные, так и непарные ошибки.

Следовательно, я хотел бы знать, как предотвратить проверку модели до тех пор, пока не завершится проверка не-поля, сохранив вызов в моей базе данных.

Попытка решения

Я пытаюсь пройти через источник DRF, чтобы выяснить, где это происходит, но мне не удалось найти то, что мне нужно переопределить, чтобы заставить это работать.

4b9b3361

Ответ 1

Поскольку, скорее всего, в поле username установлено значение unique=True, Django REST Framework автоматически добавляет валидатор, который проверяет, что новое имя пользователя уникально. Фактически вы можете подтвердить это, выполнив repr(serializer()), который покажет вам все автоматически сгенерированные поля, которые включают в себя валидаторы.

Проверка выполняется в определенном, недокументированном порядке

Таким образом, проблема, которую вы видите, заключается в том, что валидация на уровне поля вызывается перед проверкой уровня на уровне сериализации. Хотя я бы не рекомендовал его, вы можете удалить валидатор на уровне поля, установив extra_kwargs в ваш metalalizer meta.

class Meta:
    extra_kwargs = {
        "username": {
            "validators": [],
        },
    }

Вам нужно будет повторно выполнить проверку unique в вашей собственной проверке, хотя вместе с любыми дополнительными валидаторами, которые были автоматически сгенерированы.

Ответ 2

Я не верю, что вышеупомянутые решения уже работают. В моем случае у моей модели есть поля "first_name" и "last_name", но API получит только "имя".

Настройка "extra_kwargs" и "валидаторы" в мета-классе, кажется, не имеет никакого эффекта, имя first_name и last_name всегда считаются обязательными, и валидаторы всегда вызываются. Я не могу перегрузить поля символов first_name/last_name с помощью

anotherrepfor_first_name = serializers.CharField(source=first_name, required=False)

поскольку имена имеют смысл. После многих часов разочарования я нашел единственный способ переопределить валидаторы с экземпляром ModelSerializer, чтобы переопределить инициализатор класса следующим образом (простить неправильный отступ):

class ContactSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True)

class Meta:
    model = Contact
    fields = [ 'name', 'first_name', 'last_name', 'email', 'phone', 'question' ]

def __init__(self, *args, **kwargs):
    self.fields['first_name'] = serializers.CharField(required=False, allow_null=True, allow_blank=True)
    self.fields['last_name'] = serializers.CharField(required=False, allow_null=True, allow_blank=True)
    return super(ContactSerializer, self).__init__(*args, **kwargs)

def create(self, validated_data):
    return Contact.objects.create()

def validate(self, data):
    """
    Remove name after getting first_name, last_name
    """
    missing = []
    for k in ['name', 'email', 'question']:
        if k not in self.fields:
            missing.append(k)
    if len(missing):
        raise serializers.ValidationError("Ooops! The following fields are required: %s" % ','.join(missing))
    from nameparser import HumanName
    names = HumanName(data['name'])
    names.capitalize()
    data['last_name'] = names.last
    if re.search(r'\w+', names.middle):
        data['first_name'] = ' '.join([names.first, names.middle]) 
    else:
        data['first_name'] = names.first
    del(data['name'])

    return data

Теперь в документе говорится, что разрешение пустым и нулевым символьным полям - нет, но это сериализатор, а не модель, и, поскольку API вызывается всеми видами ковбоев, мне нужно покрыть мои базы.