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

DRF中扩展用户模型的Patch方法实现问题求助

解决DRF中扩展用户模型的PATCH更新问题

看起来你的代码里有几个关键问题导致Profile的bio无法正确更新,我来一步步帮你修复:

1. 先修正Profile模型的字段定义

你的bio字段定义不完整,Django的CharField必须指定max_length,而且OneToOneField在Django 2.0+之后需要加上on_delete参数:

from django.contrib.auth.models import User
from django.db import models

class Profile(models.Model):
    user = models.OneToOneField(User, unique=True, on_delete=models.CASCADE)
    bio = models.CharField(max_length=500, blank=True, null=True)  # 补充长度,允许为空更合理

2. 调整序列化器以支持正确的数据映射

你现在的序列化器把bio作为顶层字段,但发送的JSON里bio嵌套在profile对象里,这就导致数据无法正确匹配。这里有两种方案:

方案A:保持序列化器的顶层bio字段,调整请求JSON

如果用你原来的序列化器,请求的JSON应该改成这样(把bio放到顶层):

{ "email": "231@sda.com", "bio": "Cant send request" }

然后需要重写序列化器的update方法,手动处理Profile的更新:

from rest_framework import serializers
from django.contrib.auth.models import User
from .models import Profile

class UserEditSerializer(serializers.ModelSerializer):
    bio = serializers.CharField(source='profile.bio', required=False, allow_blank=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name', 'bio']

    def update(self, instance, validated_data):
        # 取出profile相关的字段
        profile_data = validated_data.pop('profile', {})
        bio = profile_data.get('bio')
        
        # 先更新User模型本身的字段
        instance = super().update(instance, validated_data)
        
        # 更新或创建Profile的bio
        profile, created = Profile.objects.get_or_create(user=instance)
        if bio is not None:
            profile.bio = bio
            profile.save()
        
        return instance

方案B:修改序列化器支持嵌套的profile结构(匹配你当前的请求JSON)

如果你想保持请求里的嵌套结构,就用嵌套序列化器:

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ['bio']

class UserEditSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer(required=False)

    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name', 'profile']

    def update(self, instance, validated_data):
        # 取出嵌套的profile数据
        profile_data = validated_data.pop('profile', None)
        
        # 更新User字段
        instance = super().update(instance, validated_data)
        
        # 处理Profile的更新
        if profile_data:
            profile, created = Profile.objects.get_or_create(user=instance)
            profile.bio = profile_data.get('bio', profile.bio)
            profile.save()
        
        return instance

这样你原来的请求JSON就能正常工作了:

{ "email": "231@sda.com", "profile": {"bio": "Cant send request" } }

3. 修正视图逻辑中的错误

你的视图有两个问题:

  • User.objects.get(user__id=request.user.id) 完全没必要,request.user就是当前登录的User对象,而且User模型没有user字段,这行代码会直接报错。
  • 使用ReadOnlyModelViewSet不太合适,因为你要做更新操作,用普通的APIView或者UpdateAPIView更简洁。

修正后的视图:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import User
from .serializers import UserEditSerializer

class UserUpdateAPIView(APIView):
    permission_classes = [IsAuthenticated]  # 确保只有登录用户能访问

    def patch(self, request):
        user_obj = request.user  # 直接获取当前用户
        serializer = UserEditSerializer(user_obj, data=request.data, partial=True)
        
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        # 返回具体的错误信息,方便调试
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

最后测试注意事项

  • 确保请求头里带上正确的认证信息(比如Token),否则request.user会是匿名用户,无法更新。
  • 如果是第一次更新用户的bio,get_or_create会自动创建对应的Profile对象,不用担心Profile不存在的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:07:30