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
相关产品推荐
相关产品推荐

