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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:42:16