Django REST Framework 如何为GET请求跳过默认权限类校验
Django REST Framework 中GET请求绕过默认权限规则的实现方案
两种尝试的失效原因
@permission_classes([AllowAny])装饰器不生效:该装饰器是为函数视图设计的,类视图的权限实例化、校验逻辑统一走get_permissions方法,不会识别类实例方法上绑定的该装饰器配置。- 重写
get_permissions时报local variable 'permission_classes' referenced before assignment错误:仅在self.action == "list"的分支内定义了permission_classes变量,POST、PUT、PATCH、DELETE对应的create、update、partial_update、destroy动作不会进入该分支,变量未声明就被引用,直接触发作用域错误。
正确实现代码
通过重写get_permissions方法,针对需要放开权限的动作单独返回权限实例,其余动作复用默认权限配置即可:
class BlogViewSet(viewsets.ModelViewSet): queryset = Blog.objects.all() serializer_class = BlogSerializer pagination_class = BlogPagination lookup_field = 'blog_slug' permission_classes = [IsOwnerOrReadOnly & IsAuthorGroup] def get_permissions(self): # 针对list动作(即GET请求的博客列表接口)放开权限 if self.action == "list": return [AllowAny()] # 其余所有动作沿用类上定义的默认权限规则 return super().get_permissions() # 若不需要自定义列表返回逻辑,可直接删除下方list方法,使用ModelViewSet自带实现即可 def list(self, request, *args, **kwargs): # 不要直接硬写Blog.objects.all(),调用self.get_queryset()可复用类上的queryset配置、过滤逻辑 queryset = self.filter_queryset(self.get_queryset()).order_by("id") # 走分页逻辑,保证类上配置的BlogPagination生效 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
补充说明
- 如果需要放开所有GET类型请求的权限(包含单条博客详情的
retrieve接口),只需要把判断条件替换为if self.request.method == "GET":,即可同时放行列表、详情两类GET请求。 - 非放行分支直接调用
super().get_permissions()即可,不需要重复手写默认权限类列表,后续修改类级别的permission_classes配置时不需要同步调整该方法逻辑。 - 原自定义
list方法中判断request.method == "GET"属于冗余逻辑:视图集的list动作本身就只会映射GET方法的列表路由,不会接收其他类型请求。
内容的提问来源于stack exchange,提问作者boyenec
相关产品推荐
相关产品推荐

