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

使用Fetch发送POST请求时DRF无法接收数据的问题排查

问题描述

我正在开发一个SoundCloud克隆项目,前端使用静态文件,后端基于Django REST Framework(DRF),文件存储在AWS上。当用Fetch发送包含文件的POST请求时,后端返回错误:

django.db.utils.IntegrityError: null value in column "name" of relation "cloudsound_song" violates not-null constraint

前端通过console.log确认数据并非空值,但后端无法接收表单数据,此前还出现过500错误。

尝试给模型字段添加null=true后,请求能成功创建数据,但所有字段均为null,示例如下:

{
    "id": 31,
    "image": null,
    "name": null,
    "audio_file":null,
    "created_on": "2023-01-07T03:20:55.104324Z"
}

后端代码

app/views.py

class SongViewSet(viewsets.ModelViewSet):
    queryset = Song.objects.all()
    content_type ='multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
    serializer_class = SongSerializer
    parser_classes = [parsers.MultiPartParser, parsers.FormParser, parsers.JSONParser, parsers.FileUploadParser]
    http_method_names = ['get', 'post', 'patch', 'delete']
    
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

app/serializers.py

class SongSerializer(serializers.HyperlinkedModelSerializer):
    content_type ='multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
    name = serializers.CharField(required=False )
    image = serializers.FileField(required=False)
    audio_file = serializers.FileField(required=False)
    class Meta :
        model = Song
        fields = ('id',  'image', 'name', 'audio_file', 'created_on')
    
    def create(self, validated_data):
        song = Song.objects.create(
            name=validated_data.get('name'),
            image=validated_data.get('image'),
            audio_file=validated_data.get('audio_file'),
        )

        song.save()

        return song

app/models.py

class Song(models.Model):
    name = models.CharField(max_length=100, )
    image = models.FileField(upload_to='./media/', default='./media/default-cover-art_tVe9r28.png' )
    audio_file = models.FileField(upload_to='./media/')
    created_on = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

解决方案
  1. 移除硬编码的content_type
    你在ViewSet和Serializer中硬编码了content_type,会覆盖DRF自动处理的请求头,导致表单数据解析失败。直接删除这两行:

    • ViewSet中的content_type ='multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
    • Serializer中的content_type ='multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
  2. 修正Serializer的字段必填设置
    模型中name和audio_file是必填字段(未设置null或blank),但Serializer里将它们设为required=False,会导致即使前端传值,Serializer也可能不校验,进而validated_data中无对应字段。修改如下:

    class SongSerializer(serializers.HyperlinkedModelSerializer):
        name = serializers.CharField()  # 移除required=False
        image = serializers.FileField(required=False)
        audio_file = serializers.FileField()  # 移除required=False
        class Meta :
            model = Song
            fields = ('id', 'image', 'name', 'audio_file', 'created_on', 'owner')  # 新增owner字段
    
  3. 规范前端Fetch请求格式
    确保前端使用FormData传递数据,且不要手动设置Content-Type头(浏览器会自动处理multipart/form-data的boundary)。示例:

    const formData = new FormData();
    formData.append('name', '歌曲名称');
    formData.append('image', imageFile);
    formData.append('audio_file', audioFile);
    
    fetch('/api/songs/', {
        method: 'POST',
        body: formData,
        headers: {
            'Authorization': 'Bearer ' + token  // 仅添加必要的认证头
        }
    });
    
  4. 优化Serializer的create方法
    Song.objects.create()已自动完成数据保存,无需额外调用song.save();同时要兼容perform_create传入的owner字段:

    def create(self, validated_data):
        return Song.objects.create(**validated_data)
    
  5. 模型字段路径优化
    模型中image的upload_to建议使用相对路径(如'covers/'),而非./media/,Django会自动结合MEDIA_ROOT处理存储路径。

内容的提问来源于stack exchange,提问作者GermBurg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:35:51