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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:45:21