JSONField嵌套表示的序列化程序

用户

在我的应用程序中,有一个模型将配置存储在其中一个字段中。字段定义为JSONField。我有一个严格的结构来定义这个字段的内容应该是什么样子,但是我正在努力寻找一种方法来序列化它来验证API请求中的数据。在

目前有效的解决方案是盲目接受符合json对象的任何内容,但不验证config_field内部的内容:

我的模型的简化版本:

class MyModel(models.Model):
    config_field = JSONField(...)
    ...

对于这个问题,这里是存储在config_field中的数据结构的简化版本:

^{pr2}$

下面是我的序列化程序的简化版本:

class MyModelSerializer(serializers.ModelSerializer):
        config_field = serializers.JSONField(required=False)
        class Meta:
            model = MyModel
            fields = ('config_field', ...)

不过,我想实现的是为config_field内部的嵌套表示(reference to DRF documentation)提供一个序列化程序。到目前为止,我尝试过的方法(但不起作用):

class ConfigVarsSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=True)

class ConfigFieldsSerializer(serializers.Serializer):
    some_config_int = serializers.IntegerField(required=True)
    some_config_vars = serializers.ListField(child=ConfigVarsSerializer,required=True)

class MyModelSerializer(serializers.ModelSerializer):
            config_field = ConfigFieldsSerializer(required=False)
            class Meta:
                model = MyModel
                fields = ('config_field', ...)

这样,POST/PUT一个带有配置的对象是可选的,但是如果config_field在请求的主体中,则应该提供整个嵌套对象。在


已被浏览了643次
更新日期: 2020-10-22 23:29:53
2 个回答
fefe Tyson

您正在发送针对config_field字段的数据,因此,您的数据应该包含该键。所以有效载荷应该如下所示

{"config_field": {"some_config_int": 42, "some_config_vars": ["foo", "bar"]}}

更新-1

在序列化程序中使用DictField()

^{pr2}$
评论 - 2020年9月22日 13:38
fefe Tyson

在尝试了几种可能的解决方案后,我想指出两个最简单也是最重要的解决方案,即不需要对MyModelSerializer或内部序列化程序重写create方法:

  1. 重写MyModelSerializerconfig_field的字段验证方法
  2. 重写由MyModelSerializer序列化的整个对象的validate方法

表示config_field内部内容的序列化程序对于这两个解决方案是相同的:

class ConfigVarsSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=True)

class ConfigFieldsSerializer(serializers.Serializer):
    some_config_int = serializers.IntegerField(required=True)
    some_config_vars = serializers.ConfigVarsSerializer(required=True, many=True)

Note that some_config_vars stores list of objects, that's why many=True.


解决方案1

重写MyModelSerializerconfig_field的字段验证方法。在给定的示例中,序列化程序的最终代码为:

^{pr2}$

此方法首先使用默认的JSONFieldSerializer验证config_field,如果内容不是有效的JSON对象,则引发异常。在

如果JSONFieldSerializer不引发异常,则调用validate_custom_fields,并将字段的内容传递到ConfigFieldsSerializer中,并为自身和所有嵌套序列化程序验证所有内容。在


解决方案2

重写由MyModelSerializer序列化的整个对象的validate方法。在给定的示例中,序列化程序的最终代码为:

class MyModelSerializer(serializers.ModelSerializer):
        config_field = JSONField(required=False)
        class Meta:
            model = MyModel
            fields = ('config_field', ...)

        def validate(self, attrs):
            config_field = attrs.get('config_field')
            if config_field:
                serializer = ConfigFieldsSerializer(data=config_field)
                serializer.is_valid(raise_exception=True)
            return attrs

这种方法需要多一点代码,但允许将config_field的验证与其他相关字段相结合。在

评论 - 2020年9月22日 13:38

最新Python问答

推荐Python问答