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

使用DRF和Ajax保存用户资料时出现KeyError: 'profile'求助

解决DRF嵌套序列化器的KeyError问题

你遇到的KeyError: 'profile'核心原因很明确:前端发送的数据结构和后端嵌套序列化器期望的格式不匹配。你的UserSerializer将profile定义为嵌套的ProfileSerializer,所以DRF要求客户端发送的数据必须把Profile相关字段包裹在profile这个键下,但你的Ajax代码是把所有字段平级发送的,导致后端无法从validated_data中取出profile键。

下面分步骤给出修复方案:

1. 修正前端Ajax的数据结构

首先要调整profileData的结构,把属于Profile模型的字段(avatar、dob、headline等)放到profile嵌套对象中,User模型的字段(first_name、last_name)保持平级:

$("#saveProfile").click(function(e) {
    e.preventDefault();
    var profileData = {
        // User模型字段
        'first_name': $("#first_name").val(),
        'last_name': $("#last_name").val(),
        // Profile模型字段,嵌套在profile键下
        'profile': {
            'avatar': $("#avatar").val(),
            'country': $("#country").val(),
            'location': $("#location").val(),
            'cp': $("#postal_code").val(),
            'headline': $("#headline").val(),
            'dob': $("#dob").val(),
            'facebook': $("#facebook").val(),
            'twitter': $("#twitter").val(),
            'github': $("#github").val(),
            'website': $("#website").val()
            // 如果background有上传控件,也需要添加进来
            // 'background': $("#background").val(),
        }
    }
    $.ajax({
        type: 'PATCH',
        url: "{% url 'profiles:api_profile' username=request.user.username %}",
        data: JSON.stringify(profileData),
        contentType: 'application/json; charset=utf-8',
        success: function(res) {
            console.log(res.data);
        },
        error: function(res) {
            console.log(res);
        }
    });
});

2. 修复视图层的返回逻辑

你的patch方法存在一个小问题:调用super().patch()后,你重新获取了实例并序列化,但其实可以直接基于更新后的实例返回数据,确保返回的是最新的用户资料:

class ProfileRetrieveAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAuthenticatedOrReadOnly, )
    lookup_field = 'username'

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        response = {
            "message": "Successfully retrieved",
            "data": serializer.data,
            "status_code": status.HTTP_200_OK
        }
        return Response(response)

    def patch(self, request, *args, **kwargs):
        instance = self.get_object()
        # 执行更新操作
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        updated_instance = serializer.save()
        
        # 序列化更新后的实例
        updated_serializer = self.get_serializer(updated_instance)
        response = {
            "message": "Perfil actualizado con éxito",
            "data": updated_serializer.data,
            "status_code": status.HTTP_200_OK
        }
        return Response(response, status=status.HTTP_200_OK)

3. 处理文件上传的额外说明

如果你的avatar或background是图片上传字段,上面的JSON格式无法传输文件,需要改用FormData来处理:

$("#saveProfile").click(function(e) {
    e.preventDefault();
    var formData = new FormData();
    // User字段
    formData.append('first_name', $("#first_name").val());
    formData.append('last_name', $("#last_name").val());
    // Profile字段,使用嵌套格式
    formData.append('profile[avatar]', $("#avatar")[0].files[0]);
    formData.append('profile[country]', $("#country").val());
    formData.append('profile[location]', $("#location").val());
    // 其他Profile字段...
    
    $.ajax({
        type: 'PATCH',
        url: "{% url 'profiles:api_profile' username=request.user.username %}",
        data: formData,
        contentType: false, // 让浏览器自动设置正确的Content-Type
        processData: false, // 禁止jQuery处理FormData
        success: function(res) {
            console.log(res.data);
        },
        error: function(res) {
            console.log(res);
        }
    });
});

这样调整后,后端的validated_data中就会包含profile键,你的update方法就能正常取出Profile数据进行更新了。

内容的提问来源于stack exchange,提问作者Miguel Toledano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:15:35