Angular上传图片至Django REST API报提交数据非文件错误求解
报错根因定位
这个报错的本质是Django REST Framework(DRF)接收到的product_image字段内容,完全不符合multipart/form-data协议要求的文件二进制流格式——要么被序列化成了普通JSON对象,要么请求头编码配置错误。你用Postman能正常传图,说明DRF端的图片字段配置、存储权限、路由逻辑全是正常的,问题完全出在前端传参的流程上。
分步骤修复操作
- 第一点:提交时必须手动构建
FormData实例,不能直接把表单整体序列化后传JSON
大部分人踩坑的原因是直接把Angular Reactive Form的value整体当请求体传,这时候选中的File对象会被Angular默认转成普通文本字符串,DRF拿到的只是"[object File]"这种无效内容,自然会提示提交的不是文件。
正确的构建逻辑要写在add-product.component.ts的提交方法里:// 从表单取出真实的图片File对象 const selectedImage = this.productForm.controls['product_image'].value as File; // 新建空的FormData容器 const submitData = new FormData(); // 逐个把普通文本、数字类型的字段塞进去 submitData.append('product_name', this.productForm.controls['product_name'].value); submitData.append('product_price', this.productForm.controls['product_price'].value); // 单独把图片文件绑定到和Serializer一致的字段名上 submitData.append('product_image', selectedImage, selectedImage.name); - 第二点:发送请求时绝对不要手动指定
Content-Type头
很多人为了传multipart格式,手动在请求头里写'Content-Type': 'multipart/form-data',这会导致请求头缺失浏览器自动生成的boundary边界分隔符,DRF根本没法拆分出文件内容。对应的api.service.ts里的方法要这么写:// api.service.ts 新增商品接口 createProduct(submitData: FormData) { // 不要在这个请求的config里手动覆盖任何Content-Type配置,让浏览器自动生成适配FormData的请求头 return this.http.post('/api/products/', submitData); } - 第三点:文件选择控件要正确绑定真实的File对象
普通的双向绑定拿不到input[type=file]里的真实文件,必须通过change事件把选中的文件写入对应的FormControl,对应的add-product.component.html写法:
对应的ts事件处理方法:<!-- 图片选择控件 --> <input type="file" accept="image/*" (change)="handleImageSelect($event)" >handleImageSelect(event: Event) { const fileList = (event.target as HTMLInputElement).files; if (fileList?.length) { // 把真实File对象写入表单控件 this.productForm.patchValue({ product_image: fileList[0] }); } }
容易漏查的踩坑点
- 检查全局HTTP拦截器,是不是给所有请求统一加了
Content-Type: application/json的请求头,这个全局配置会覆盖FormData的自动请求头,直接导致文件传输格式失效。 - 核对FormData里append的字段名,要和DRF Serializer里定义的
product_image完全一致,哪怕是大小写不匹配、多打个下划线,都会让DRF找不到对应的文件字段触发报错。
内容的提问来源于stack exchange,提问作者John13
相关产品推荐
相关产品推荐

