Django REST Framework: повышение ошибки при добавлении дополнительных полей в POST

Когда вы пишете сериализатор, тривиально указывать, какие поля будут включены (через Meta fields), устанавливая права на чтение и запись на них и проверяя их. Тем не менее, мне было интересно узнать, есть ли простой способ указать, что только ожидаемые ожидаемые поля и любые дополнительные ключи должны были вызывать ошибку.

например. скажем, у меня есть сериализатор

class ModelASerializer(serializers.ModelSerializer):

    class Meta:
        model = models.ModelA
        fields = ('name', 'number')

Предположим далее, что у меня нет никаких проверок.

И я POST загружаю эту полезную нагрузку для создания нового экземпляра

{
    "name": "test",
    "number": 5
}

Все в порядке.

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

{
    "name": "test",
    "number": 5,
    "title": "Mr"
}

Однако сериализатор просто игнорирует дополнительный ключ, не создавая исключение.

Итак, мой вопрос: есть ли способ заставить сериализатор ожидать только поля, указанные в fields или - если это не теги ModelSerializer -, указанные как члены, и вызывать ошибку, если это не случай?

Ответ 1

Наткнулся на этот вопрос и обнаружил, что с помощью проверки уровня объекта немного проще. Это влечет за собой простое определение метода проверки:

class ModelASerializer(serializers.ModelSerializer):
    ...
    def validate(self, data):
        if hasattr(self, 'initial_data'):
            unknown_keys = set(self.initial_data.keys()) - set(self.fields.keys())
            if unknown_keys:
                raise ValidationError("Got unknown fields: {}".format(unknown_keys))
        return data

Ответ 2

Вы можете сделать это, переопределив метод is_valid() для сериализатора. Здесь мы проверим, не является ли какой-либо ключ в payload не полеми сериализатора с использованием функций filter() и lambda.

Если filter() возвращает некоторые поля, которые не входят в поля сериализатора, тогда мы поднимаем ValidationError. В противном случае мы вызываем метод super(), и он будет выполнять обычную валидацию сериализатора.

from django.core.exceptions import ValidationError

class MySerializer(..):

    def is_valid(self, raise_exception=False):
        if hasattr(self, 'initial_data'):
            payload_keys = self.initial_data.keys() # all the payload keys
            serializer_fields = self.fields.keys() # all the serializer fields
            extra_fields = filter(lambda key: key not in serializer_fields , payload_keys) 
            if extra_fields:
                raise ValidationError('Extra fields %s in payload'%extra_fields)
        return super(MySerializer, self).is_valid(raise_exception)