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

React Native图片无法保存至Django模型的问题求助

问题描述

我正在开发首个React Native应用,后端采用Django框架,需将设备图库中的图片发送至Django服务器并保存到Profile模型的ImageField中。目前遇到的问题是:打印profile.image仅显示文件名,缺少"image/"前缀,且Django后台管理界面中图片字段为空。

React Native代码

const sendI = async (image) => {
  
    const formData = new FormData()
    let image_data = {
      uri : image.uri,
      name : image.fileName,
      type : image.type,
    }
    if (image != null){
    
      await formData.append( 'image', image_data)
      await formData.append('name', usern)
      //await formData.append('name', 'a' )
      console.log(formData)
      setSentI(formData)
      console.log('recieved')
    }

    
    console.log(image)
    
  }

  const showImagePicker = async () => {
    
    // Ask the user for the permission to access the media library 
    const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();

    if (permissionResult.granted === false) {
      alert("You've refused to allow this appp to access your photos!");
      return;
    }
    
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1,
    });

    // Explore the result
    console.log(result);

    if (!result.cancelled) {
      await setProfileImage(result);
      console.log(result.uri);
      sendI(result);
      
    }
  }

  const openCamera = async () => {
    // Ask the user for the permission to access the camera
    const permissionResult = await ImagePicker.requestCameraPermissionsAsync();

    if (permissionResult.granted === false) {
      alert("You've refused to allow this appp to access your camera!");
      return;
    }

    const result = await ImagePicker.launchCameraAsync();

    // Explore the result
    console.log(result);

    if (!result.cancelled) {
      setProfileImage(result);
      console.log(result);
    }
  }

  const image = () => {
    console.log(sentI)
    fetch(server + `home/imagetest/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      body: sentI, 
    })
    .then( res => res.json())
    .then( res => {
      console.log(res)
    })
    .catch( error => console.log(error))
  }

Django代码

models.py

class Profile(models.Model):
  image = models.ImageField(upload_to="images/", blank=True)

views.py

@csrf_exempt
def imagetest(request):
    if request.method == "POST":
        print(request.FILES)
        image = request.FILES.get('image', False)
        user = request.POST.get('name', False)
        print(image)
        print(user)
        userid = User.objects.get(username=user).id
        profile = Profile.objects.get(id=userid)
        profile.image = image
        print(profile)
        print(profile.image)

urls.py(项目根目录)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/', include('home.urls')),
    path('auth/', obtain_auth_token),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

urls.py(home应用)

router = routers.DefaultRouter()
router.register('users', UserViewSet)
router.register('profiles', ProfileViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('login/', views.login),
    path('signup/', views.signup),
    path('profile/', views.setprofile),
    path('profileimg/', views.setprofileimg),
    path('checkprofile1/', views.checkprofile1),
    path('checkprofile2/', views.checkprofile2),
    path('matchfriends/', views.matchfriends),
    path('getRequesting/', views.getRequesting),
    path('acceptRe/', views.acceptRe),
    path('denyRe/', views.denyRe),
    path('request/', views.request),
    path('unrequest/', views.unrequest),
    path('imagetest/', views.imagetest),
    path('counttest/', views.counttest),
]

settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
STATIC_URL = '/static/'

解决方案

1. 保存Django模型实例(最关键)

你的视图中仅设置了profile.image = image,但未调用profile.save()方法。Django不会自动保存模型修改,必须显式调用该方法才能将文件写入MEDIA_ROOT/images/目录并更新数据库记录:

@csrf_exempt
def imagetest(request):
    if request.method == "POST":
        print(request.FILES)
        image = request.FILES.get('image')
        user_name = request.POST.get('name')
        
        if not image or not user_name:
            return JsonResponse({'error': '缺少图片或用户名'}, status=400)
        
        try:
            user = User.objects.get(username=user_name)
            # 推荐通过外键关联查询Profile,避免ID不匹配问题
            profile = Profile.objects.get(user=user)
            profile.image = image
            profile.save()  # 必须调用此方法完成保存
            print(profile.image)  # 现在会显示images/文件名格式
            return JsonResponse({'success': True})
        except User.DoesNotExist:
            return JsonResponse({'error': '用户不存在'}, status=404)
        except Profile.DoesNotExist:
            return JsonResponse({'error': '用户档案不存在'}, status=404)

2. 修复React Native的FormData请求

  • 移除手动设置的Content-Type:使用FormData时,fetch会自动生成带正确边界的multipart/form-data请求头,手动设置会导致服务器无法解析文件。
  • 处理iOS URI格式:iOS返回的URI以file://开头,需要去掉前缀才能正确上传:
import { Platform } from 'react-native';

const sendI = async (image) => {
    if (!image) return;
    
    const formData = new FormData();
    // 适配iOS URI格式
    const uri = Platform.OS === 'ios' ? image.uri.replace('file://', '') : image.uri;
    const image_data = {
        uri: uri,
        name: image.fileName || 'profile.jpg',  // 兜底文件名
        type: image.type || 'image/jpeg',       // 兜底文件类型
    };
    
    formData.append('image', image_data);
    formData.append('name', usern);
    
    setSentI(formData);
}

const image = () => {
    if (!sentI) return;
    fetch(server + `home/imagetest/`, {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
        },
        body: sentI, 
    })
    .then(res => res.json())
    .then(res => console.log(res))
    .catch(error => console.log(error))
}

3. 完善Profile模型的关联

确保Profile与User通过一对一外键关联,避免ID匹配错误:

from django.contrib.auth.models import User

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    image = models.ImageField(upload_to="images/", blank=True)

之后就可以通过user.profile直接获取用户的档案,无需手动匹配ID。

4. 验证文件权限

检查MEDIA_ROOT/images/目录是否存在,确保服务器对media/目录有写入权限,Django会自动创建目录,但权限不足会导致上传失败。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:30:54