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

使用Django REST Framework进行部分更新时出现KeyError问题

解决Django REST Framework Partial Update(Patch)中的KeyError 'profile'问题

让我来帮你分析下问题所在:你的UserSerializer的update方法里直接用validated_data.pop('profile')来获取嵌套的profile数据,但当你发送不包含profile字段的Patch请求(比如你只更新username)时,validated_data里根本没有'profile'这个键,自然就触发了KeyError。另外你的update方法里还有个潜在问题:不管请求里有没有传password,你都强制调用user.set_password(validated_data['password']),这同样会在Patch没传密码时报错。

下面是修复后的完整方案:

1. 修正UserSerializer的update方法

我们需要做三个关键调整:

  • 用安全方式获取profile数据,避免KeyError
  • 只在请求包含password字段时才更新密码
  • 用嵌套序列化器处理profile的部分更新,让代码更可扩展

修改后的序列化器代码:

class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        exclude = ("user", )

class UserSerializer(serializers.ModelSerializer):
    profile = UserProfileSerializer(partial=True)

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = super(UserSerializer, self).create(validated_data)
        # 创建时必须设置密码,直接处理
        user.set_password(validated_data['password'])
        user.save()
        # 用序列化器更新profile更规范
        profile_serializer = UserProfileSerializer(user.profile, data=profile_data)
        if profile_serializer.is_valid():
            profile_serializer.save()
        return user

    def update(self, instance, validated_data):
        # 安全获取profile数据,没有则返回空字典
        profile_data = validated_data.pop('profile', {})
        # 先更新user的基础字段
        user = super().update(instance, validated_data)
        # 仅当请求包含password时才更新密码
        if 'password' in validated_data:
            user.set_password(validated_data['password'])
            user.save()
        # 有profile数据时才更新
        if profile_data:
            profile_serializer = UserProfileSerializer(user.profile, data=profile_data, partial=True)
            if profile_serializer.is_valid():
                profile_serializer.save()
        return user

    class Meta:
        model = User
        exclude = ("groups", "user_permissions", )

2. 移除自定义的partial_update方法

你不需要在UserViewSet里写自己的partial_update方法,因为ModelViewSet已经集成了UpdateModelMixin,它会自动处理Partial Update请求,只要你的序列化器支持partial模式(你已经在profile = UserProfileSerializer(partial=True)里设置了)。

你的视图可以保持原来的样子:

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    model = User

测试验证

现在你发送Patch请求{ "username": "insomnia77" }时:

  • validated_data里没有'profile'键,profile_data会是空字典
  • 代码会跳过profile的更新逻辑,只更新username字段
  • 不会再触发KeyError

如果需要同时更新profile字段,比如发送:

{
  "username": "insomnia77",
  "profile": {
    "company": "New Company"
  }
}

序列化器也会正确处理profile的部分更新。

内容的提问来源于stack exchange,提问作者Joey Fran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:57:37