通过Serializer为用户添加/更新权限无生效且无报错问题排查
问题排查与解决方案
核心问题分析
你的代码存在两个关键问题导致权限更新无效果且无报错:
- 序列化器字段未正确配置:
user_permissions字段未显式定义为可写入的关联字段,导致请求中的权限数据未经过序列化器验证,也未进入validated_data;直接读取request.data跳过了验证流程,可能存在数据类型不匹配(如字符串ID而非整数)的问题。 - 权限数据处理逻辑不规范:未从经过验证的
validated_data中获取权限数据,而是直接操作原始请求数据,且未处理权限数据不存在的场景。
排查步骤
- 检查请求数据格式:确认前端传入的
user_permissions是整数ID数组(如{"user_permissions": [1,3,5]}),而非字符串数组或其他格式。 - 验证权限范围:当前视图仅要求登录权限,若修改的是其他用户的权限,需确保当前用户拥有
auth.change_user权限(或自定义权限),否则Django权限系统会静默阻止操作。 - 添加调试日志:在序列化器的
update方法中打印validated_data和permissions,确认数据是否正确传入。 - 直接检查数据库:查看
auth_user_user_permissions表,确认权限关联数据是否被写入,排除ORM缓存干扰。
修复后的代码
序列化器(UpdateSerializer)
from django.contrib.auth.models import Permission from rest_framework import serializers from django.contrib.auth.models import User class UpdateSerializer(serializers.ModelSerializer): """Handle serialization and deserialization of User objects.""" # 显式定义可写入的权限字段,自动验证ID有效性 user_permissions = serializers.PrimaryKeyRelatedField( many=True, queryset=Permission.objects.all(), write_only=True # 若不需要在返回结果中返回权限,保留此配置 ) class Meta: model = User fields = [ "email", "password", "tel", "first_name", "last_name", "registration_id", "avatar", "is_deleted", "user_permissions", ] extra_kwargs = { "is_deleted": {"write_only": True}, "password": {"write_only": True}, } def update(self, instance, validated_data): """Perform an update on a User.""" password = validated_data.pop("password", None) # 从验证后的数据中取出权限,无则跳过 permissions = validated_data.pop("user_permissions", None) if permissions is not None: # set方法自动处理关联关系,支持传入对象或主键ID instance.user_permissions.set(permissions) # 更新其他字段 for key, value in validated_data.items(): setattr(instance, key, value) if password is not None: instance.set_password(password) instance.save() return instance
用户视图(UpdateUserView)
无需重写 update 方法,复用父类默认实现即可:
from rest_framework import generics, status from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User class UpdateUserView(generics.RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] # 若需修改其他用户权限,建议替换为IsAdminUser或自定义权限 # permission_classes = [IsAdminUser] serializer_class = UpdateSerializer queryset = User.objects.all()
内容的提问来源于stack exchange,提问作者Taha Omar
相关产品推荐
相关产品推荐

