如何在Django REST Framework中动态设置read_only实现字段权限控制
问题1:self.user.id无法正确获取已认证用户的解决方法
DRF序列化器实例本身没有user属性,当前登录的认证用户默认存放在序列化器的context上下文中,由视图实例化序列化器时自动传入,正确获取方式如下:
# 序列化器内获取当前用户 request = self.context.get('request') if not request or not request.user.is_authenticated: # 可自行处理未认证场景,比如抛出权限异常 current_user = request.user user_id = current_user.id
问题2:customize_read_only方法是否需要更名
不需要更名,因为DRF本身不会自动调用你自定义的customize_read_only方法,就算改为update也不符合逻辑:update是序列化器用于执行数据更新的原生方法,不是用来返回序列化器类的。
如果你要沿用拆分管理员、普通用户两类序列化器的思路,应该把选择序列化器的逻辑迁移到视图层,重写视图的get_serializer_class原生钩子方法,该方法会被DRF自动调用。
问题3:整体实现思路的问题
你拆分不同权限序列化器的方向是对的,但实现路径存在错误:
- 序列化器本身不负责选择自身使用哪个子类,该逻辑属于视图层的职责
- 你当前写在
UsersSerializer中的自定义方法没有调用入口,完全不会生效 - 原有代码存在语法错误:两个子序列化器的类定义末尾多写了一个右括号,会直接导致运行失败
可直接运行的实现方案
这里提供两种常用实现方式,按需选择即可:
方案1:视图层动态选择序列化器(沿用你拆分两类序列化器的思路)
- 先修正序列化器代码:
class ForAdmins(serializers.ModelSerializer): class Meta: model = User fields = '__all__' class ForUsers(serializers.ModelSerializer): class Meta: read_only_fields = ['email','is_role_veryfied','is_email_veryfied'] model = User fields = '__all__'
- 在对应的视图类中重写
get_serializer_class方法:
from rest_framework.viewsets import ModelViewSet class UserViewSet(ModelViewSet): queryset = User.objects.all() # DRF会自动调用该方法获取对应序列化器 def get_serializer_class(self): if self.request.user.is_authenticated and self.request.user.id == 1: return ForAdmins return ForUsers
方案2:单个序列化器动态调整只读字段(无需拆分多类序列化器)
不需要定义多个序列化器,直接重写单个序列化器的get_fields方法即可:
class UsersSerializer(QueryFieldsMixin, serializers.ModelSerializer): class Meta: model = User fields = '__all__' def get_fields(self): fields = super().get_fields() request = self.context.get('request') # 非id=1的用户,指定字段自动设为只读 if request and request.user.is_authenticated and request.user.id != 1: readonly_fields = ['email','is_role_veryfied','is_email_veryfied'] for field_name in readonly_fields: if field_name in fields: fields[field_name].read_only = True return fields
内容的提问来源于stack exchange,提问作者Ali Husham
相关产品推荐
相关产品推荐

