Django中run_validation移除QueryDict嵌套序列化字段的解决方法
问题:DRF序列化器run_validation移除嵌套字段dress_sizes
场景:使用自定义MultipartJsonParser处理Multipart/form-data请求(包含JSON数据和图片),序列化器中定义了嵌套字段dress_sizes = SizeSerializer(many=True, required=False),但经过run_validation后,该字段从验证数据中消失,导致create方法无法获取。
代码示例
序列化器代码
class CreateSerializer(ModelSerializer[Dress]): dress_sizes = SizeSerializer(many=True, required=False) def run_validation(self, data: Any = ...) -> Any | None: return super(CreateSerializer, self).run_validation(data) def validate(self, data): return super().validate(data)
自定义解析器代码
class MultipartJsonParser(MultiPartParser): def parse(self, stream, media_type=None, parser_context=None): result = super().parse( stream, media_type=media_type, parser_context=parser_context ) data = {} for key, value in result.data.items(): if type(value) != str: data[key] = value continue if "{" in value or "[" in value: try: data[key] = json.loads(value) except ValueError: data[key] = value else: data[key] = value qdict = QueryDict('', mutable=True) qdict.update(data) return DataAndFiles(qdict, result.files)
数据变化
- run_validation前的请求数据:
< QueryDict: { 'file_name': ['swimsuit.svg'], 'dress_sizes': [ [{ 'size': 'xs' }, { 'size': 's' }, { 'size': 'm' }, { 'size': 'l' }, { 'size': 'xl' }] ], 'image': [ < TemporaryUploadedFile: swim.svg(image / svg + xml) > ] } >
- run_validation后的验证数据:
OrderedDict([('file_name', 'swimsuit.svg'), ('image', < TemporaryUploadedFile: swim.svg(image / svg + xml) > )])
原因分析
问题出在自定义解析器的最后一步:将处理后的data字典更新到QueryDict中时,QueryDict的update方法会把列表类型的值再次包裹一层列表。原本解析后的dress_sizes是一维数组[{...}, {...}],经过QueryDict处理后变成了嵌套列表[[{...}, {...}]],而DRF的嵌套序列化器SizeSerializer(many=True)只能识别一维列表,因此run_validation时无法匹配字段规则,直接丢弃了该字段。
解决方案
移除解析器中转换QueryDict的步骤,直接返回处理后的普通字典即可,DRF序列化器可以直接处理字典类型的输入:
修改后的解析器代码:
class MultipartJsonParser(MultiPartParser): def parse(self, stream, media_type=None, parser_context=None): result = super().parse( stream, media_type=media_type, parser_context=parser_context ) data = {} for key, value in result.data.items(): # 用isinstance替代type判断,更严谨 if not isinstance(value, str): data[key] = value continue if "{" in value or "[" in value: try: data[key] = json.loads(value) except ValueError: data[key] = value else: data[key] = value # 直接返回普通字典,无需转换为QueryDict return DataAndFiles(data, result.files)
修改后,dress_sizes会以一维列表的形式传入序列化器,run_validation就能正确识别并保留该字段,后续的validate和create方法也能正常获取到数据。
内容的提问来源于stack exchange,提问作者Sardar Faisal
相关产品推荐
相关产品推荐

