如何使 rest_framework 序列化器禁止多余的字段?
Posted
技术标签:
【中文标题】如何使 rest_framework 序列化器禁止多余的字段?【英文标题】:How to make a rest_framework Serializer disallow superfluous fields? 【发布时间】:2014-04-16 16:08:24 【问题描述】:我注意到序列化器在拒绝未知字段的输入时并不是很严格:
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
在这种情况下出现意外的验证错误?
【问题讨论】:
【参考方案1】:这绝对有效:
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)
【讨论】:
专业提示:set(some_dict)
和set(some_dict.keys())
一样好用【参考方案2】:
使用 django REST framework 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)
【讨论】:
【参考方案3】:s.data
不包含 bar
那么重要的用例是什么?
查看文档后,我没有看到原生解决方案。您可以覆盖.validate()
进行检查并以这种方式提高ValidationErrors
。我没有用 when 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
【讨论】:
我喜欢这种方法,但validate
在 restore_fields
之后被调用,所以它看不到额外的输入条目,我需要在其他地方插入。我的用例是一个常规的 REST API - 我认为如果存在意外的 POST 参数,它应该会引发错误,以便用户在例如输入错误的可选参数。
你说得对,我很抱歉。我通过在.validate()
方法中添加attrs['bar'] = 'blah'
进行测试。
另一种可能的解决方案,虽然我不认为它是干净的。您可以在.validate()
中访问self.context['request']._request.POST
。您必须过滤掉某些键,例如 csrfmiddleware
和 _method
,但您会得到用户实际提供的内容,并且可以将其与 self.fields.keys()
进行比较。以上是关于如何使 rest_framework 序列化器禁止多余的字段?的主要内容,如果未能解决你的问题,请参考以下文章
python Django Rest_Framework框架 模型类序列化器(ModelSerializer)详解(图文并茂版)
python Django Rest_Framework框架 模型类序列化器(ModelSerializer)详解(图文并茂版)
python Django Rest_Framework框架 APIView介绍与序列化器详解(图文并茂版)