Django REST Framework更新用户头像报非文件提交错误排查
问题描述
更新用户资料头像时,序列化器无法正常执行更新保存逻辑,打印错误信息为:The submitted data was not a file. Check the encoding type on the form.', code='invalid')
需求为完成用户信息更新后,将数据返回给Flutter应用端展示,接口不需要返回HTML格式内容。
核心问题原因
- 请求头配置错误:上传文件时使用了
Content-Type: application/json,该格式无法传输二进制文件流,ImageField字段会将传入的字符串路径判定为非法非文件类型,直接抛出校验错误 - 代码笔误:序列化器文件中定义的是
UserProfileSerializer,视图逻辑中实例化的是不存在的UserUpdateSerializer,会直接触发命名错误 - 序列化器配置缺失:未开启部分更新参数,非全字段传参时会触发校验失败,且校验失败后未返回错误信息,直接返回序列化器数据导致无法定位问题,也不会触发save保存逻辑
- 请求参数错误:传入的
image字段值是服务器侧的文件路径字符串,不是用户上传的真实文件二进制流,不符合ImageField的参数接收规则
修复步骤
1. 修正序列化器配置
补全字段校验规则,允许部分字段更新,修正后serializers.py代码如下:
from rest_framework import serializers from django.contrib.auth.models import User from .models import UserProfile class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'username', 'email'] extra_kwargs = { 'username': {'required': False}, 'email': {'required': False} } class UserProfileSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ['image'] extra_kwargs = { 'image': {'required': False} }
2. 修正视图逻辑
修正序列化器引用错误,增加异常捕获和统一JSON返回结构,校验失败时返回明确错误信息,修正后views.py代码如下:
from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from django.contrib.auth.models import User from .models import UserProfile from .serializers import UserSerializer, UserProfileSerializer @api_view(['POST', 'PUT']) def user_update(request, pk): try: user = User.objects.get(pk=pk) except User.DoesNotExist: return Response( {"code": 404, "msg": "指定用户不存在"}, status=status.HTTP_404_NOT_FOUND ) user_profile, _ = UserProfile.objects.get_or_create(user=user) # 开启partial=True支持部分字段更新 user_serializer = UserSerializer(instance=user, data=request.data, partial=True) profile_serializer = UserProfileSerializer(instance=user_profile, data=request.data, partial=True) if user_serializer.is_valid() and profile_serializer.is_valid(): user_serializer.save() profile_serializer.save() return Response({ "code": 200, "msg": "用户信息更新成功", "data": { "base_info": user_serializer.data, "profile": profile_serializer.data } }) return Response( { "code": 400, "msg": "参数校验失败", "errors": {**user_serializer.errors, **profile_serializer.errors} }, status=status.HTTP_400_BAD_REQUEST )
3. 优化模型层保存逻辑
增加文件路径存在性判断,避免默认图或路径异常时触发IO错误,修正后models.py代码如下:
from django.db import models from django.contrib.auth.models import User from PIL import Image import os class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, null=True) image = models.ImageField(upload_to='user', default='default.png') def save(self, *args, **kwargs): super().save(*args, **kwargs) # 仅当图片文件真实存在时才做裁剪处理 if self.image and os.path.exists(self.image.path): img = Image.open(self.image.path) if img.height > 300 or img.width > 300: output_size = (300, 300) img.thumbnail(output_size) img.save(self.image.path)
4. 调整请求规则
- 上传头像时请求头不要设置
Content-Type: application/json,改用multipart/form-data格式,Flutter端使用multipart请求方式,将选中的头像图片作为文件字段传入,不要传服务器侧的图片路径字符串 - 如果不需要更新头像,请求参数中不要传
image字段,序列化器会保留原有头像路径 - DRF的
Response类默认返回JSON格式数据,不会返回HTML内容,可直接被Flutter端解析渲染
内容的提问来源于stack exchange,提问作者Pascal
相关产品推荐
相关产品推荐

