如何制作rest_framework Serializer不允许多余的字段?

时间:2014-03-12 13:25:18

标签: python django api rest django-rest-framework

我注意到,在拒绝未知字段的输入时,Serializer并不是非常严格:

In [1]: from rest_framework import serializers

In [2]: class TestSerializer(serializers.Serializer):
   ...:     foo = serializers.CharField()
   ...:     

In [3]: s = TestSerializer(data=dict(foo='foo', bar='bar'))

In [4]: s.is_valid()
Out[4]: True

有没有办法配置Serializer以在这种情况下返回有关bar意外的验证错误?

3 个答案:

答案 0 :(得分:6)

这肯定有效:

class TestSerializer(serializers.Serializer):
    foo = serializers.CharField()

    def validate(self, attrs):
        unknown =  set(self.initial_data) - set(self.fields)
        if unknown:
            raise ValidationError("Unknown field(s): {}".format(", ".join(unknown)))
        return attrs

嵌套和列出序列化程序

如果您将此类序列化程序用作另一个序列化程序中的字段,则无效。在这种情况下,子序列化程序将无法访问初始数据,您将获得异常。

ListSerializer(或many=True)相同,因为列表序列化程序的子序列化程序无法获取单个initial_data项(此处有一个github ticket

在这种情况下,两种情况都不太清洁的解决方案是:

from rest_framework.fields import empty
from rest_framework.settings import api_settings

class TestSerializer(serializers.Serializer):
    foo = serializers.CharField()

    def run_validation(self, data=empty):
        if data is not empty:
            unknown = set(data) - set(self.fields)
            if unknown:
                errors = ["Unknown field: {}".format(f) for f in unknown]
                raise serializers.ValidationError({
                    api_settings.NON_FIELD_ERRORS_KEY: errors,
                })

        return super(TestSerializer, self).run_validation(data)

答案 1 :(得分:1)

s.data不包含bar那么重要的用例是什么?

在查看文档之后,我没有看到本机解决方案。您可以覆盖.validate()进行检查并以此方式提升ValidationErrors。我在partial=True时没有对此进行测试,所以如果您正在使用它,我们会检查一下。

class TestSerializer(serializers.Serializer):
    foo = serializers.CharField()

    def validate(self, attrs):
        has_unknown_fields = set(attrs.keys()) - set(self.fields.keys())

        if has_unknown_fields:
            raise serializers.ValidationError("dont send extra fields")

        return attrs

答案 2 :(得分:1)

使用django REST框架v.3.3.0,它将是:

class _FieldSetValidatingSerializer(serializers.Serializer):
  def is_valid(self, raise_exception=False):
    super().is_valid(False)

    fields_keys = set(self.fields.keys())
    input_keys = set(self.initial_data.keys())

    additional_fields = input_keys - fields_keys

    if bool(additional_fields):
      self._errors['fields'] = ['Additional fields not allowed: {}.'.format(list(additional_fields))]

    if self._errors and raise_exception:
      raise ValidationError(self.errors)

    return not bool(self._errors)