Python 如何使用Django Rest框架使用序列化程序验证动态JSON?
我有一个接受JSON的API。JSON数据有一个名为Python 如何使用Django Rest框架使用序列化程序验证动态JSON?,python,django,django-rest-framework,Python,Django,Django Rest Framework,我有一个接受JSON的API。JSON数据有一个名为type的键,它应该是一个选择字段,并且在5个指定类型中有一个值。比如说A,B,C,D&E JSON可以有不同的字段,这取决于值是A、B、C、D还是E。如何验证可能存在或不存在的其他字段?这个问题有两个部分: 如何验证多个字段 如何仅验证某些输入的字段子集 我将分别回答这两个问题 如何验证多个字段 Django REST框架允许您通过覆盖序列化程序上的validate方法来验证多个字段。这是最后一次完成的,在所有其他验证器运行之后,并且有一
type
的键,它应该是一个选择字段,并且在5个指定类型中有一个值。比如说A,B,C,D&E
JSON可以有不同的字段,这取决于值是A、B、C、D还是E。如何验证可能存在或不存在的其他字段?这个问题有两个部分:
- 如何验证多个字段
- 如何仅验证某些输入的字段子集
validate
方法来验证多个字段。这是最后一次完成的,在所有其他验证器运行之后,并且有一个关于它的问题
def validate(self, attrs):
if "type" in attrs:
the_type = attrs["type"]
if the_type == "A":
# Check if "a_field" was actually passed
if "a_field" not in attrs:
raise ValidationError({"a_field": self.error_messages["required"]})
# Check that it's "great"
if attrs["a_field"] != "great":
raise Va class DemoSerializer(serializers.Serializer):
type = serializers.ChoiceField(choices=types)
a_field = serializers.CharField(required=False)
def to_representation(self, instance):
optional_fields = {
"B": ["a_field"],
}
data = super(DemoSerializer, self).to_representation(instance)
instance_type = data["type"]
if instance_type in optional_fields:
remove_fields = optional_fields[instance_type]
for field in remove_fields:
if field in data:
data.pop(field)
return datalidationError({"a_field": self.error_messages["not_great"]})
return attrs
仅当类型为“a”
时,才会验证a\u字段
如何仅验证某些输入的字段子集
这是一个棘手的部分,因为默认情况下,Django REST框架不会通过序列化程序传递数据,而序列化程序的键不在字段中。因此,在我们的示例中,如果您没有向列表中添加a_字段
,则始终会触发一个错误,即该字段是必需的,即使数据已传入。这意味着您需要将所有可选字段添加到序列化程序中,并将它们标记为required=False
class DemoSerializer(serializers.Serializer):
type = serializers.ChoiceField(choices=types)
a_field = serializers.CharField(required=False)
这有一个不幸的副作用,即在使用序列化程序序列化数据时,使所有这些可选字段都显示出来,但这是可以通过将重写为\u表示来解决的问题。您需要提前知道要删除哪些字段
class DemoSerializer(serializers.Serializer):
type = serializers.ChoiceField(choices=types)
a_field = serializers.CharField(required=False)
def to_representation(self, instance):
optional_fields = {
"B": ["a_field"],
}
data = super(DemoSerializer, self).to_representation(instance)
instance_type = data["type"]
if instance_type in optional_fields:
remove_fields = optional_fields[instance_type]
for field in remove_fields:
if field in data:
data.pop(field)
return data
这将允许您根据返回的类型删除字段列表。感谢您的详细解释。我的第一种方法是为每个类型创建不同的序列化程序,并让它们从父类型继承公共字段。看来,走这条路是不可能的。它必须是一个单独的序列化程序,所有字段都已预先声明,但where required设置为false。