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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:30:20