Python 如何使用Django Rest框架使用序列化程序验证动态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方法来验证多个字段。这是最后一次完成的,在所有其他验证器运行之后,并且有一

我有一个接受JSON的API。JSON数据有一个名为
type
的键,它应该是一个选择字段,并且在5个指定类型中有一个值。比如说A,B,C,D&E


JSON可以有不同的字段,这取决于值是A、B、C、D还是E。如何验证可能存在或不存在的其他字段?

这个问题有两个部分:

  • 如何验证多个字段
  • 如何仅验证某些输入的字段子集
我将分别回答这两个问题

如何验证多个字段

Django REST框架允许您通过覆盖序列化程序上的
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。