You need to enable JavaScript to run this app. 如何在Django REST Framework中动态设置read_only实现字段权限控制
优惠活动
大模型
产品
解决方案
定价
更多

如何在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:视图层动态选择序列化器(沿用你拆分两类序列化器的思路)

  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__'
  1. 在对应的视图类中重写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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 03:15:03