如何在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
相关产品推荐
相关产品推荐

