You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework向request.data添加列表元素出现嵌套列表问题求解

问题原因

出现嵌套列表报错的根因是QueryDict类型的特殊存储逻辑:Django的QueryDict用来处理多值字段时,直接赋值或append操作会把传入的整个列表当作单个元素存入对应key的value列表中,最终生成[['3','4']]的嵌套结构,序列化器无法将嵌套列表解析为合法UUID格式。

解决方案

方案1:兼容QueryDict原生方法处理

QueryDict自带setlist方法专门用来给多值字段赋值一维列表,修改后代码如下:

def post(self, request, format=None):
    """ Creates a Post instance """
    is_querydict = isinstance(request.data, QueryDict)
    if is_querydict:
        request.data._mutable = True

    tmp_new_tags = request.data.get('new_tags', None)
    tag_ids = []
    if tmp_new_tags:
        new_tags = request.data.pop('new_tags')
        # 兼容QueryDict.pop返回列表的特性
        tag_list = new_tags[0] if is_querydict and isinstance(new_tags[0], list) else new_tags
        for new_tag in tag_list:
            tag = Tag.objects.create(name=new_tag, user=self.request.user)
            tag_ids.append(str(tag.id))
    
    # 分类型给tags赋值
    if is_querydict:
        request.data.setlist('tags', tag_ids)
    else:
        request.data['tags'] = tag_ids

    serializer = PostSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save(user=self.request.user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

方案2:拷贝数据独立处理(更推荐)

不要直接修改原始request.data,拷贝出独立数据处理完成后再传给序列化器,完全规避QueryDict的特性问题:

def post(self, request, format=None):
    """ Creates a Post instance """
    # 拷贝请求数据避免修改原始request
    req_data = request.data.copy()
    tmp_new_tags = req_data.pop('new_tags', None)
    tag_ids = []

    if tmp_new_tags:
        # 兼容QueryDict返回列表的特殊情况
        if isinstance(tmp_new_tags, list) and len(tmp_new_tags) == 1 and isinstance(tmp_new_tags[0], list):
            tmp_new_tags = tmp_new_tags[0]
        for new_tag in tmp_new_tags:
            tag = Tag.objects.create(name=new_tag, user=self.request.user)
            tag_ids.append(str(tag.id))
    
    req_data['tags'] = tag_ids
    serializer = PostSerializer(data=req_data)
    if serializer.is_valid():
        serializer.save(user=self.request.user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
补充校验

需要确认PostSerializer中tags字段显式设置many=True,否则序列化器默认按单值处理,也会引发解析报错:

class PostSerializer(serializers.ModelSerializer):
    """ Serializer for Post create, update, delete model """
    tags = serializers.PrimaryKeyRelatedField(queryset=Tag.objects.all(), many=True)
    class Meta:
        model = Post
        fields = ('title', 'body', 'description', 'publish', 'tags')

如果前端请求直接传Content-Type: application/json格式参数,request.data会默认为普通Python字典,不会触发QueryDict相关问题,也不需要修改_mutable属性。

内容的提问来源于stack exchange,提问作者Fer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:36:08