如何使用APIView的update方法更新自定义User模型字段
问题描述
我正尝试编写APIView的update方法,用来修改自定义AbstractUser模型中的字段。查了APIView的官方文档和相关示例,但大多要么是一对一关联的「profile」模型,要么需要写序列化器——我觉得用户模型不需要序列化器(如果我错了请指正)。现在不确定怎么给用户模型实现对应的update方法。
我要从前端更新自定义User模型里的referred_count和tokens字段,模型代码如下:
users/models.py
class User(AbstractUser): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) username = None first_name = models.CharField(max_length=100, default="unknown") last_name = models.CharField(max_length=100, default="unknown", blank=True) profile_pic = models.CharField(max_length=200, default="unknown") premium = models.BooleanField(default=False) referred_count = models.IntegerField(default=0) tokens = models.IntegerField(default=0) email = models.EmailField(unique=True, db_index=True) secret_key = models.CharField(max_length=255, default=get_random_secret_key) USERNAME_FIELD = "email" REQUIRED_FIELDS = [] objects = UserManager() class Meta: swappable = "AUTH_USER_MODEL"
我的users/api.py里的UpdateFields视图类update方法还没正确实现:
users/api.py
class UpdateFields(ApiAuthMixin, ApiErrorsMixin, APIView): def update(self, request, *args, **kwargs): # update various user fields based on request.data # I am not sure what should go inside here. return request.user.update(request, *args, **kwargs)
希望前端发送如下格式的JSON,通过UpdateFields APIView用PATCH方式更新这些字段:
{ "tokens": 100, "referred_count": 12 }
我的users/urls.py配置如下:
users/urls.py
urlpatterns = [ path("me/", UserMeApi.as_view(), name="me"), path("update/", UpdatePremium.as_view(), name="update"), ]
解决方案
首先纠正你的认知:即便是自定义User模型,使用序列化器依然是DRF推荐的最佳实践。序列化器能帮你做数据校验、字段过滤,还能统一API输入输出格式,避免直接操作模型字段带来的安全风险(比如前端恶意修改premium、secret_key这类敏感字段)。
下面分两种方式实现:
方式一:使用序列化器(推荐)
1. 编写User序列化器
在users/serializers.py中创建序列化器,只暴露允许更新的字段:
from rest_framework import serializers from .models import User class UserPartialUpdateSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['referred_count', 'tokens']
2. 完善UpdateFields视图的update方法
修改users/api.py:
from rest_framework.response import Response from rest_framework import status from .serializers import UserPartialUpdateSerializer class UpdateFields(ApiAuthMixin, ApiErrorsMixin, APIView): def patch(self, request, *args, **kwargs): # 获取当前登录用户 user = request.user # partial=True允许部分字段更新 serializer = UserPartialUpdateSerializer(user, data=request.data, partial=True) # 校验数据,不合法直接抛出异常 serializer.is_valid(raise_exception=True) # 保存更新 serializer.save() # 返回更新后的数据 return Response(serializer.data, status=status.HTTP_200_OK) # 兼容PUT方法(全量更新),直接复用PATCH逻辑 def update(self, request, *args, **kwargs): return self.patch(request, *args, **kwargs)
3. 修正URL配置
注意urls.py里的视图类名错误,改成UpdateFields.as_view():
urlpatterns = [ path("me/", UserMeApi.as_view(), name="me"), path("update/", UpdateFields.as_view(), name="update"), ]
方式二:不使用序列化器(不推荐)
如果坚持不使用序列化器,需要手动做数据校验和字段过滤,避免安全风险:
from rest_framework.response import Response from rest_framework import status class UpdateFields(ApiAuthMixin, ApiErrorsMixin, APIView): def patch(self, request, *args, **kwargs): user = request.user # 定义允许更新的字段白名单 allowed_fields = ['referred_count', 'tokens'] # 过滤请求数据,只保留白名单内的字段 update_data = {k: v for k, v in request.data.items() if k in allowed_fields} # 手动校验数据类型必须是整数 for field, value in update_data.items(): if not isinstance(value, int): return Response( {field: "必须是整数类型"}, status=status.HTTP_400_BAD_REQUEST ) # 更新并保存用户字段 for field, value in update_data.items(): setattr(user, field, value) user.save() # 返回更新后的字段 return Response({ 'referred_count': user.referred_count, 'tokens': user.tokens }, status=status.HTTP_200_OK)
注意事项
- 确保
ApiAuthMixin已正确处理用户认证,保证只有登录用户能修改自己的字段。 - 优先使用序列化器,它能处理大部分数据校验和安全问题,代码更简洁易维护。
- 如果需要实现增量更新(比如tokens增加N而不是直接设置为某个值),可以在序列化器的
update方法里自定义逻辑,或者在视图中单独处理。
内容的提问来源于stack exchange,提问作者Tyler Kim
相关产品推荐
相关产品推荐

