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

Vue3前端POST文件至Django DRF遇Serializer KeyError问题求助

问题解答

1. DRF处理序列化器的时机与validated_data和request.data的区别

  • DRF并非请求一抵达接口就处理序列化器,而是在ViewSet的create/update等核心方法执行时,才会初始化序列化器并调用is_valid()完成数据验证与格式转换。
  • validated_data和request.data完全不同:
    • request.data是前端发送的原始请求数据,包含未经过滤、验证的内容,格式可能不符合序列化器要求;
    • validated_data是序列化器经过is_valid()验证、转换后得到的合规数据,只有通过验证的字段才会被保留在这里。

2. 出现uploaded_images KeyError的原因

核心问题有两个:

前端数据格式错误

你前端直接将普通JS对象传给Axios的post方法,但发送multipart/form-data请求必须使用原生FormData对象。普通对象中的数组uploaded_images会被Axios自动序列化为uploaded_images.0、uploaded_images.1这类键名,DRF的ListField无法识别这种格式,导致序列化器验证时无法解析出uploaded_images字段,自然不会出现在validated_data中。

后端代码未做容错处理

虽然你给uploaded_images设置了required=False,但在create方法中直接执行validated_data.pop('uploaded_images'),如果字段不存在就会触发KeyError,应该先判断字段是否存在再处理。

另外,后端PostImage.objects.create里的字段名写错了:你的PostImageSerializer中定义的是image字段,但代码里写的是images = uploaded_item,这会导致数据库字段不匹配的问题。

3. 查看服务端接收与验证的数据的方法

  • 查看原始请求数据:在PostViewSet的create方法中添加打印语句:
    def create(self, request, *args, **kwargs):
        print("原始请求数据:", request.data)
        return super().create(request, *args, **kwargs)
    
  • 查看验证后的数据:在PostSerializer的create方法开头添加打印:
    def create(self, validated_data):
        print("验证后的数据:", validated_data)
        # 后续原有代码
    
  • 开发环境下开启Django的DEBUG=True,控制台会输出详细的请求和调试信息,也可以借助Django Debug Toolbar工具更直观查看请求数据。

修复建议

前端代码修改

将普通对象替换为FormData,手动添加所有字段,文件数组需要循环添加:

function submitPost() {
    const formData = new FormData();
    // 添加普通字段
    formData.append('category', fields.value.category.index);
    formData.append('body', fields.value.body);
    formData.append('can_view', fields.value.audience);
    formData.append('can_comment', fields.value.cancomment);
    formData.append('video', fields.value.video);
    formData.append('user', store.userId);
    // 添加图片数组
    fields.value.images.forEach(image => {
        formData.append('uploaded_images', image);
    });

    // 从cookie中获取CSRF token,替换原模板语法
    const csrfToken = document.cookie.match(/csrftoken=([^;]+)/)[1];
    axios.post('api/v1/posts/create/', formData, {
        headers: {
            "X-CSRFToken": csrfToken
        }
    })
    .then((response) => {
        if(response.status == 201){
            store.messages.push("Post created successfully")
        }
    })
    .catch((error) => {
        messages.value.items.push(error.message)
    })
}

后端代码修改

在create方法中先判断uploaded_images是否存在,同时修正PostImage的字段名:

def create(self, validated_data):
    # 先判断字段是否存在,不存在则返回空数组
    uploaded_data = validated_data.pop('uploaded_images', [])
    new_post = Post.objects.create(**validated_data)
    for uploaded_item in uploaded_data:
        # 修正字段名为image,对应PostImage模型的字段
        PostImage.objects.create(post=new_post, image=uploaded_item)
    return new_post

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:15:29