Django Rest+React Dropzone上传图片报错:提交数据非文件
问题原因与修复方案
问题根源
你的Quote模型中photos字段是单个ImageField,但上传时传递的是文件列表(前端多次调用formData.append('photos', file),后端用getlist获取列表),序列化器验证时发现传入的是列表而非单个文件,因此抛出"The submitted data was not a file"错误。
方案1:适配单张图片上传(保留现有模型)
React端修改
限制Dropzone仅允许选择单张图片,并只上传第一个文件:
function ImageUploader() { const [fileNames, setFileNames] = useState([]); const handleDrop = async (acceptedFiles) => { try { const formData = new FormData(); // 仅取第一个文件 const targetFile = acceptedFiles[0]; if (!targetFile) return; formData.append('photos', targetFile); // 注释手动设置的Content-Type,axios会自动生成带boundary的正确头 const response = await axios.post('http://localhost:8000/api/quotes/create/', formData, { headers: { 'Accept': 'application/json', }, }); console.log('Upload successful:', response.data.message); setFileNames([targetFile.name]); } catch (error) { console.error('Upload failed:', error); } }; return ( <div className="App"> <Dropzone onDrop={handleDrop} accept={{ mimeType: ["image/jpeg", "image/png"] }} minSize={1024} maxSize={3072000} maxFiles={1} // 新增:限制最多选1张图 > {/* Dropzone内容 */} </Dropzone> </div> ); }
Django后端修改
视图中改用get获取单个文件,而非getlist:
class QuoteCreateAPIView(APIView): def post(self, request, format=None): if 'photos' in request.data: # 单文件上传,用get而非getlist serializer = QuoteSerializer(data={'photos': request.FILES.get('photos')}, partial=True) else: serializer = QuoteSerializer(data=request.data, partial=True) # 后续逻辑保持不变 if serializer.is_valid(): # ... 原有保存/更新逻辑 return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
方案2:支持多张图片上传(修改模型结构)
如果需求是上传多张图片,需要调整模型设计(单个ImageField无法存储多文件):
1. 重构模型
新建Photo模型关联Quote:
class Photo(models.Model): quote = models.ForeignKey(Quote, on_delete=models.CASCADE, related_name='photos') image = models.ImageField(upload_to='photos/') # 修改Quote模型,删除原photos字段 class Quote(models.Model): quote_id = models.CharField(max_length=10, unique=True, default=get_unique_quote_id) # ... 其他原有字段 # 移除原photos字段:photos = models.ImageField(upload_to='photos/', ) date_time = models.DateTimeField(auto_now_add=True, null=True)
2. 更新序列化器
新增PhotoSerializer并修改QuoteSerializer支持多图:
class PhotoSerializer(serializers.ModelSerializer): class Meta: model = Photo fields = ('image',) class QuoteSerializer(serializers.ModelSerializer): make = serializers.CharField() model = serializers.CharField() variant = serializers.CharField(required=False) photos = PhotoSerializer(many=True, required=False) # 新增多图序列化 class Meta: model = Quote fields = '__all__' # ... 原有extra_kwargs保持不变 def create(self, validated_data): photos_data = validated_data.pop('photos', []) # 原有创建Quote的逻辑 make_name = validated_data.pop('make') model_name = validated_data.pop('model') variant_name = validated_data.pop('variant', None) make, _ = CarMake.objects.get_or_create(make=make_name) model, _ = CarModel.objects.get_or_create(model=model_name, make=make) variant, _ = ModelVariant.objects.get_or_create(variant=variant_name, make=make, model=model) quote = Quote.objects.create(make=make, model=model, variant=variant, **validated_data) # 创建关联的图片记录 for photo in photos_data: Photo.objects.create(quote=quote, **photo) return quote
3. 调整视图逻辑
上传图片时直接传递request.data给序列化器(无需手动构造):
class QuoteCreateAPIView(APIView): def post(self, request, format=None): if 'photos' in request.data: # 多图上传直接用request.data serializer = QuoteSerializer(data=request.data, partial=True) else: serializer = QuoteSerializer(data=request.data, partial=True) # 后续逻辑保持不变 if serializer.is_valid(): # ... 原有保存/更新逻辑 return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. React端保持现有逻辑
无需修改上传代码,保持多次formData.append('photos', file)即可支持多图上传。
内容的提问来源于stack exchange,提问作者mr_no
相关产品推荐
相关产品推荐

