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

DRF generics.RetrieveUpdateDestroyAPIView非管理员访问报无权限问题

问题原因

非管理员用户访问被拦截的核心原因是permissions.py中自定义权限类IsUserOrIsAdmin的逻辑和当前Booking接口的业务场景不匹配,和get_queryset方法无关:

  • 该权限类的非管理员放行条件为isinstance(obj, User) and request.user == obj,仅当操作对象是User模型实例、且实例对应当前登录用户时才放行,但你当前视图操作的是Booking模型实例,该判断条件永远不成立
  • 最终非管理员用户访问时,仅request.user.is_staff为True(也就是管理员)的分支能通过校验,其余用户全部被拦截返回权限错误
修复步骤

1. 修正自定义权限类逻辑

适配Booking接口的权限规则,重写IsUserOrIsAdmin类:

from rest_framework.permissions import BasePermission

class IsUserOrIsAdmin(BasePermission):
    """管理员可访问所有预订记录,普通用户仅可访问自己名下的预订记录"""
    def has_permission(self, request, view):
        # 校验用户已登录
        return bool(request.user and request.user.is_authenticated)

    def has_object_permission(self, request, view, obj):
        # 管理员直接放行
        if request.user.is_admin:
            return True
        # 普通用户仅可操作自身关联的Booking记录
        return obj.user == request.user

2. (可选)简化get_queryset写法

你当前的get_queryset逻辑本身没有问题,可以简化为更简洁的写法,不简化也能正常运行:

class BookingRetrtieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [IsUserOrIsAdmin]
    serializer_class = BookingSerializer

    def get_queryset(self):
        if self.request.user.is_admin:
            return Booking.objects.all()
        return Booking.objects.filter(user=self.request.user)

注意:RetrieveUpdateDestroyAPIView在执行单资源操作时,会先从queryset中取出对应id的对象再做对象权限校验,保留queryset按用户过滤的逻辑可以避免越权遍历id获取其他用户的记录,和权限类形成双重校验,建议保留。

内容的提问来源于stack exchange,提问作者Naveen Pandia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:12:21