我注意到,在拒绝未知字段的输入时,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
意外的验证错误?
答案 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)