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

如何在React中用FormData发送嵌套对象数组并在DRF中保存

解决FormData提交嵌套数组到Django REST Framework的问题

问题根源

JSON格式的嵌套数组(如songs: [{title: "abc", duration: "5"}])能被DRF自动解析,但FormData的嵌套字段格式(songs[0][title])需要DRF的解析器正确处理,同时前端的FormData构造逻辑、后端视图的解析器配置都要匹配要求。

分步解决方案

1. 修正前端FormData构造逻辑

  • 移除空图片的空字符串提交:无文件时不要添加singerimg字段,避免触发ImageField的格式校验错误
  • 确保嵌套数组的字段格式符合DRF解析要求

修改后的前端代码:

var formData = new FormData();
formData.append('name', $('#name').val());
formData.append('age', $('#age').val());

// 仅当存在文件时才提交图片字段
const imageFile = $('#image')[0].files[0];
if (imageFile) {
    formData.append('singerimg', imageFile);
}

// 嵌套歌曲数组的正确格式:按索引递增构造字段
formData.append('songs[0][title]', 'abc');
formData.append('songs[0][duration]', '50');
// 多首歌时依次递增索引:songs[1][title], songs[1][duration]...

2. 配置后端视图的解析器

在处理请求的视图类中,必须添加MultiPartParser和FormParser,确保DRF能正确解析multipart/form-data格式的请求:

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from .serializers import singerSerializer

class SingerCreateAPIView(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def post(self, request):
        serializer = singerSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

3. 备选方案:JSON字符串传递嵌套数组

如果上述方案仍无法解析嵌套数组,可将歌曲序列化为JSON字符串提交,后端手动解析:

前端修改:

var formData = new FormData();
formData.append('name', $('#name').val());
formData.append('age', $('#age').val());

if ($('#image')[0].files[0]) {
    formData.append('singerimg', $('#image')[0].files[0]);
}

// 将歌曲数组转为JSON字符串提交
const songs = JSON.stringify([{"title":"abc","duration":"50"}]);
formData.append('songs', songs);

后端序列化器修改:

import json
from rest_framework import serializers
from .models import singer, songs

class soSerializer(serializers.ModelSerializer):
    class Meta:
        model = songs
        fields = ['id', 'title', 'duration']

class singerSerializer(serializers.ModelSerializer):
    # 用JSONField接收字符串,仅用于写入
    songs = serializers.JSONField(write_only=True)
    # 输出时仍用嵌套序列化器返回歌曲数据
    output_songs = soSerializer(many=True, source='songs', read_only=True)

    class Meta:
        model = singer
        fields = ['id', 'name', 'age','singerimg', 'songs', 'output_songs']
    
    def create(self, validated_data):
        # 解析JSON字符串为数组
        song_data_list = validated_data.pop('songs')
        if isinstance(song_data_list, str):
            song_data_list = json.loads(song_data_list)
        
        sin = singer.objects.create(**validated_data)
        for song_data in song_data_list:
            songs.objects.create(singer=sin, **song_data)
        
        return sin

排障提示

提交请求后可查看DRF的错误响应定位问题:

  • 若提示songs字段缺失:检查前端FormData的字段名是否拼写正确
  • 若提示图片格式错误:确认仅在有文件时提交singerimg字段
  • 若提示songs不是数组:检查前端嵌套字段格式,或改用JSON字符串方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:11:10