Skip to main content
 首页 » 编程设计

python之如何使用 Django Rest Framework 使用序列化程序验证动态 JSON

2024年10月25日21JeffreyZhao

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

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

请您参考如下方法:

这个问题有两个部分:

  • 如何验证多个字段?
  • 如何只验证某些输入的字段子集?

我将分别回答这两个问题。

How do I go about validating multiple fields?

Django REST Framework 允许您通过覆盖序列化程序上的 validate 方法来验证多个字段。这是最后完成的,在所有其他验证器运行之后,并且有一个 detailed explanation in the documentation。关于它。

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 

如果 type 是 "A",这只会验证 a_field。

How do I only validate a subset of fields for some input?

这是棘手的部分,因为默认情况下 Django REST Framework 不会通过具有不在 fields 列表中的键的序列化程序传递数据。因此,如果在我们的示例中,您没有将 a_field 添加到列表中,那么即使传入了数据,也会始终触发该字段是必需的错误。这意味着您将需要将所有可选字段添加到序列化程序并将它们标记为 required=False。

class DemoSerializer(serializers.Serializer): 
    type = serializers.ChoiceField(choices=types) 
    a_field = serializers.CharField(required=False) 

这有一个不幸的副作用,即在使用序列化程序序列化数据时显示所有这些可选字段,但您可以通过覆盖 to_representation 来解决这个问题。您需要提前知道要删除哪些字段。

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 

这应该允许您根据返回的类型删除字段列表。