在我的应用程序中,有一个模型将配置存储在其一个字段中。该字段定义为<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="landing-content">
<section class="slider">
<img src="http://i.imgur.com/fVWomWz.png"/>
</section>
</div>
。我有一个严格的结构来定义该字段的内容,但是我正在努力寻找一种方法来对其进行序列化以验证API请求中的数据。
目前有效但不验证JSONField
内部内容的解决方案是盲目接受符合config_field
对象的任何内容:
我的模型的简化版本:
json
出于这个问题,这是class MyModel(models.Model):
config_field = JSONField(...)
...
中存储的数据结构的简化版本:
config_field
这是我的序列化程序的简化版本:
{"some_config_int": 42, "some_config_vars": [{"id": 1}, {"id": 2}]}
我想实现的是为class MyModelSerializer(serializers.ModelSerializer):
config_field = serializers.JSONField(required=False)
class Meta:
model = MyModel
fields = ('config_field', ...)
内部的嵌套表示形式(reference to DRF documentation)提供一个序列化程序。到目前为止,我已经尝试过(但不起作用):
config_field
通过这种方式,POST / PUT具有配置的对象将是可选的,但是如果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', ...)
位于请求的正文中,则应提供整个嵌套对象。
答案 0 :(得分:1)
您正在针对config_field
字段 发送数据 ,因此,您的数据应包含该密钥。因此有效载荷应如下所示
{"config_field": {"some_config_int": 42, "some_config_vars": ["foo", "bar"]}}
在序列化程序中将 DictField()
用作
VALID_DICT_KEYS = ['foo_1']
class ConfigFieldsSerializer(serializers.Serializer):
some_config_int = serializers.IntegerField(required=True)
some_config_vars = serializers.ListField(child=serializers.DictField(), required=True)
def validate(self, attrs):
attrs = super().validate(attrs)
some_config_vars = attrs['some_config_vars']
keys_list = []
for item in some_config_vars:
keys_list.extend(list(item.keys()))
unwanted_keys = set(keys_list) - set(VALID_DICT_KEYS)
if unwanted_keys:
raise serializers.ValidationError("raise error with some msg")
return attrs
class MyModelSerializer(serializers.Serializer):
config_field = ConfigFieldsSerializer(required=False)
class Meta:
fields = ('config_field',)
data = {'config_field': {"some_config_int": 42, "some_config_vars": [{"foo_1": "bar"}, {"foo_2": "honey"}]}}
serializer = MyModelSerializer(data=data)
serializer.is_valid(True)
print(serializer.data)
答案 1 :(得分:0)
尝试了几种可能的解决方案后,我想指出2个最简单的解决方案,最重要的是 不需要 覆盖create
而不是{{1} }或内部序列化器:
MyModelSerializer
中config_field
的字段验证方法MyModelSerializer
序列化的整个对象覆盖validate
方法表示MyModelSerializer
内部内容的序列化器对于两种解决方案都是相同的:
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)
存储对象列表,这就是some_config_vars
的原因。
覆盖many=True
中config_field
的字段验证方法。在给定示例的情况下,序列化器的最终代码为:
MyModelSerializer
此方法首先使用默认的class MyModelSerializer(serializers.ModelSerializer):
config_field = JSONField(required=False)
class Meta:
model = MyModel
fields = ('config_field', ...)
def validate_config_field(self, value):
serializer = ConfigFieldsSerializer(data=value)
serializer.is_valid(raise_exception=True)
return value
验证config_field
,如果内容不是有效的JSONFieldSerializer
对象,则会引发异常。
如果JSON
没有引发异常,则调用JSONFieldSerializer
并将字段内容传递到validate_custom_fields
并验证其自身和所有嵌套序列化程序的所有内容。
对ConfigFieldsSerializer
序列化的整个对象重写validate
方法。在给定示例的情况下,序列化器的最终代码为:
MyModelSerializer
此方法需要更多代码,但可以将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
的验证与其他相关字段结合起来。