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

Django REST Framework上传图片报错:提交数据非文件

问题原因

报错核心是3处代码错误+测试请求方式错误,Django admin走原生 Django 逻辑不经过DRF的序列化、解析器流程,所以不受配置错误影响可以正常上传:

  • 视图层解析器配置属性名拼写错误:DRF视图指定解析器的属性为parser_classes(复数),代码中写为parser_class(单数),导致配置的MultiPartParser文件解析器完全不生效,无法识别multipart格式的文件上传请求。
  • 序列化器字段声明错误:显式声明bloodbank_logo字段时直接赋值serializers.ImageField类本身,没有加括号实例化,字段校验逻辑异常。
  • 测试请求逻辑完全错误:
    1. 用json=data参数发请求时,请求编码为application/json,该格式不支持二进制文件传输;
    2. 传入的bloodbank_logo是本地文件路径字符串,不是真实的文件二进制内容,后端拿到的只是普通文本,自然判定不是合法文件。
  • 额外隐藏bug:序列化器中bloodbanks_user字段的source配置为user.username,但模型中外键字段名为bloodbank_user,不存在user属性,请求走到保存逻辑时会直接抛字段不存在的错误。
修复方案

按以下顺序修改对应代码即可:

1. 修改序列化器 serializers.py

修正字段实例化问题和source配置错误:

from rest_framework import serializers
from bloodbank_api.models import Bloodbanks


class BloodbankdataSerializer(serializers.ModelSerializer):
    # 修正source路径,匹配模型中的bloodbank_user外键字段
    bloodbanks_user=serializers.CharField(source='bloodbank_user.username',read_only=True)
    url = serializers.HyperlinkedIdentityField(
        view_name='bloodbank-detail-id',
        lookup_field='pk'
    )
    # 字段声明必须实例化,加();如果不需要自定义校验规则,这行可以直接删除,ModelSerializer会自动映射ImageField
    bloodbank_logo=serializers.ImageField()
    
    class Meta:
        model=Bloodbanks
        fields=['id','bloodbanks_user','fullbankname','apositive',
                'anegative','bpositive','bnegative','abpositive',
                'abnegative','opositive','onegative','latitude',
                'longitude','state','district','location','website',
                'bloodbank_logo','bloodbank_description','bloodbank_phone','url']

2. 修改视图层 views.py

修正解析器配置的属性名拼写:

from bloodbank_api.models import Bloodbanks
from bloodbank_api.serializers import BloodbankdataSerializer
from rest_framework import mixins,generics
from rest_framework.parsers import FormParser, MultiPartParser,JSONParser

class BloodbankDataDetail(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView):
    queryset = Bloodbanks.objects.all()
    serializer_class = BloodbankdataSerializer
    # 修正属性名为parser_classes(复数),配置才会生效
    parser_classes=(MultiPartParser, FormParser, JSONParser) 
    lookup_field = 'pk'
    def get(self, request,*args, **kwargs):
        id=kwargs.get('pk')
        if id is not None:
            return self.retrieve(request,*args, **kwargs)
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def perform_create(self, serializer):
        serializer.save(bloodbank_user=self.request.user)

3. 修改Python测试脚本

文件上传不能用JSON格式传参,需要拆分普通字段和文件字段,用data传普通参数、files传打开的文件对象,requests会自动设置正确的multipart/form-data请求头:

import requests
endpoint='http://127.0.0.1:8000/bloodbank/'
# 普通表单字段
data={
    "fullbankname": "Dirgahyu",
    "apositive": 1,
    "anegative": 1,
    "bpositive": 1,
    "bnegative": 1,
    "abpositive": 1,
    "abnegative": 1,
    "opositive": 1,
    "onegative": 1,
    "latitude": "dhdhd",
    "longitude": "hdhdd",
    "state": "dhhd",
    "district": "dhdhgd",
    "location": "dhdhdhd",
    "website": "jdjdjd",
    "bloodbank_description": "hahaha",
    "bloodbank_phone": "1234567890" # 注意该字段max_length=10,不要传超过10位的内容
}
# 二进制打开本地图片,作为文件参数传入
with open("/Users/aayushdipgiri/aayu's code/opencv/cat.jpeg", "rb") as img_file:
    files = {"bloodbank_logo": img_file}
    # 禁止用json=参数,用data和files传参
    resp = requests.post(endpoint, data=data, files=files)
print(resp.json())

4. Postman测试注意事项

不要选raw-JSON请求模式,选择form-data模式:

  • 普通文本字段直接选Text类型填值
  • bloodbank_logo字段类型选File,从本地选择要上传的图片即可

内容的提问来源于stack exchange,提问作者Aayush Dip Giri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:18:46