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

DRF ModelViewSet中根据用户权限动态选择序列化器实现方案

Django ModelViewSet 按用户权限动态切换序列化器实现方案

问题核心

get_serializer_class方法执行时,DRF还未完成待操作对象的提取,因此无法直接拿到实例传入haveProfileOwnerRights做校验。针对不同接口场景可以通过路由参数取对象ID,结合动作类型判断即可。

具体实现

1. 修正权限类的漏判逻辑

你当前的权限类没有放行只读权限用户的GET类请求,先补上对应判断:

class IsOwnerOrHaveProfileViewEditOrViewRight(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.user.is_anonymous:
            return False
        if haveProfileOwnerRights(request, obj):
            return True
        if haveProfileViewEditRights(request):
            return True
        # 只读权限仅允许安全请求(GET/HEAD/OPTIONS)
        if haveProfileViewRights(request) and request.method in permissions.SAFE_METHODS:
            return True
        return False

2. 重写get_serializer_class方法实现动态选择

针对详情类接口(retrieve/update/partial_update/destroy),直接从路由kwargs中提取pk参数查询当前操作的对象实例,再做所有者判断;列表/创建场景不需要单对象判断,直接按角色权限返回对应序列化器即可:

from django.http import Http404

class UserProfileViewSet(viewsets.ModelViewSet):
    permission_classes = [
        permissions.IsAuthenticated, IsOwnerOrHaveProfileViewEditOrViewRight
    ]
    queryset = UserProfile.objects.all()

    def get_serializer_class(self):
        # 最高优先级:拥有完全管控权限的用户,返回全量编辑序列化器
        if haveProfileViewEditRights(self.request):
            return UserProfileViewEditSerializer
        
        # 单对象操作场景:从路由取pk查询实例,判断是否为资料所有者
        target_pk = self.kwargs.get('pk')
        if target_pk is not None:
            try:
                target_profile = self.get_queryset().get(pk=target_pk)
                if haveProfileOwnerRights(self.request, target_profile):
                    return UserProfileOwnerSerializer
            except UserProfile.DoesNotExist:
                raise Http404
        
        # 创建场景:默认用户仅能编辑自身资料,返回所有者序列化器
        if self.action == 'create':
            return UserProfileOwnerSerializer
        
        # 剩余场景为只读权限,返回只读序列化器
        return UserProfileViewOnlySerializer

注意事项

  • 上述代码中查询target_profile不会产生重复数据库查询,后续DRF执行get_object()时会复用查询结果,无额外性能损耗
  • 权限判断顺序不要随意调整:完全管控权限 > 所有者权限 > 只读权限,避免高权限用户拿到低权限序列化器
  • 如果列表接口需要做数据过滤(比如普通用户仅能看到自己的资料),可以额外重写get_queryset方法加过滤逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:57:23