如何在Django中处理React Native上传的多张图片?
问题描述
我尝试从React Native客户端发送包含多张图片的数据,将图片添加到FormData中,只有发送formData._parts时POST请求能成功,但Django/DRF服务器端无法正确解析数据。
React Native客户端代码
const post = async () => { const token = await getToken(); const [description, setDescription] = useState(''); const formData = new FormData(); images.forEach((image) => { formData.append(`images`, { uri: image, type: 'image/jpeg', name: image, }); }); formData.append('description', description); console.log('formdata:', formData); try { await axios.post(URL, formData._parts, { headers: { 'Content-Type': 'multipart/form-data', Authorization: token, }, }); } catch (e) { console.log(e); } };
客户端打印的formData._parts结果:
formdata: [["images", {"name": "/Library/Developer/CoreSimulator/Devices/123.jpg", "type": "image/jpeg", "uri": "/Library/Developer/CoreSimulator/Devices/123.jpg"}], ["images", {"name": "/Library/Developer/CoreSimulator/Devices/456.jpg", "type": "image/jpeg", "uri": "/Library/Developer/CoreSimulator/Devices/456.jpg"}], ["description", "Test"]]
Django/DRF服务器端代码
models.py
class Post(models.Model): user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=None ) images = models.FileField( max_length=3000, default=None, null=True, blank=True, upload_to='media/post_images') description = models.TextField(null=False, default=None) date = models.DateTimeField(editable=False, auto_now_add=True)
serializers.py
class PostSerializer(serializers.ModelSerializer): images = serializers.FileField() class Meta: model = Post fields = "__all__"
views.py
class PostView(APIView): serializer_class = PostSerializer parser_classes = (MultiPartParser, FormParser) def post(self, request, format=None): form_data = request.data images = form_data.get('images') description = form_data.get('description') user_id = self.request.user print(form_data) post = Post.objects.create( images=images, description=description, user_id=user_id) post.save() serializer = PostSerializer(post) return Response(serializer.data, status=status.HTTP_201_CREATED)
服务器端打印的form_data结果:
<QueryDict: {'0': ['images'], '1.uri': ['/Library/Developer/CoreSimulator/Devices/123.jpg'], '1.type': ['image/jpeg'], '1.name': ['/Library/Developer/CoreSimulator/Devices/123.jpg'], '1.0': ['images'], '1.1.uri': ['/Library/Developer/CoreSimulator/Devices/456.jpg'], '1.1.type': ['image/jpeg'], '1.1.name': ['/Library/Developer/CoreSimulator/Devices/456.jpg'], '2.0': ['description'], '2.1': ['Test']}>
解决方案
1. 修正React Native客户端代码
核心问题是不应该发送formData._parts,直接传递FormData实例即可。同时注意React Native中文件URI的平台差异,以及避免手动设置multipart/form-data头部(axios会自动处理带boundary的正确头部):
const post = async () => { const token = await getToken(); // 注意:useState必须放在组件顶层,不能在async函数内部 const [description, setDescription] = useState(''); const formData = new FormData(); images.forEach((image, index) => { // iOS平台需要给URI添加file://前缀,Android直接用原路径 const fileUri = Platform.OS === 'ios' ? `file://${image}` : image; formData.append('images', { uri: fileUri, type: 'image/jpeg', // 给图片设置合理文件名,避免用完整路径 name: `post_image_${index}.jpg`, }); }); formData.append('description', description); try { await axios.post(URL, formData, { headers: { Authorization: token, // 移除手动设置的Content-Type,axios会自动生成正确的multipart头部 }, }); } catch (e) { console.log(e); } };
2. 修正服务器端代码(支持多张图片)
当前Post模型的images是单文件字段,无法存储多张图片,推荐采用关联模型的方式处理多图上传:
调整模型结构
models.py
from django.db import models from django.contrib.auth.models import User class Post(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) description = models.TextField(null=False) date = models.DateTimeField(editable=False, auto_now_add=True) # 新增关联模型存储单张图片 class PostImage(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='images') image = models.FileField(upload_to='media/post_images/')
编写序列化器
serializers.py
from rest_framework import serializers from .models import Post, PostImage class PostImageSerializer(serializers.ModelSerializer): class Meta: model = PostImage fields = ('image',) class PostSerializer(serializers.ModelSerializer): images = PostImageSerializer(many=True, required=False) class Meta: model = Post fields = ('id', 'user', 'description', 'date', 'images') def create(self, validated_data): # 分离图片数据和帖子数据 images_data = validated_data.pop('images', []) post = Post.objects.create(**validated_data) # 批量创建关联的图片记录 for image_data in images_data: PostImage.objects.create(post=post, **image_data) return post
简化视图逻辑
views.py
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.parsers import MultiPartParser, FormParser from .models import Post from .serializers import PostSerializer class PostView(APIView): serializer_class = PostSerializer parser_classes = (MultiPartParser, FormParser) def post(self, request, format=None): serializer = PostSerializer(data=request.data) if serializer.is_valid(): # 自动关联当前登录用户 serializer.save(user=self.request.user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3. 验证数据解析结果
修改后,服务器端request.data会被正确解析为:
{'description': 'Test', 'images': [<InMemoryUploadedFile>, <InMemoryUploadedFile>]}
序列化器会自动处理帖子和图片的保存逻辑。
内容的提问来源于stack exchange,提问作者jdez
相关产品推荐
相关产品推荐

