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

