DRF重写get_permissions遇TypeError:权限类无法用|运算
问题解决:Django DRF权限类组合报错TypeError
错误原因
你直接用|运算符组合自定义权限类实例(比如IsSuperAdmin()|IsOwner())是不被支持的,因为Django REST Framework的BasePermission基类没有实现__or__运算符,无法通过这种方式实现"或"逻辑的权限判断。另外你的代码还存在缩进错误(GET分支和else分支的return语句缩进不正确),这也会导致代码运行异常。
解决方案
下面提供两种可行的解决方法,你可以根据需求选择:
方法一:自定义OR组合权限类
编写一个通用的OrPermission类,用来包装多个权限类,只要其中任意一个权限通过,就允许访问:
在permissions.py中添加:
class OrPermission(BasePermission): def __init__(self, *permissions): self.permissions = permissions def has_permission(self, request, view): # 只要有一个权限类的has_permission返回True,就通过 return any(perm.has_permission(request, view) for perm in self.permissions) def has_object_permission(self, request, view, obj): # 处理对象级权限,同样只要有一个权限类通过就允许 return any(perm.has_object_permission(request, view, obj) for perm in self.permissions)
然后修改views.py中的get_permissions方法,修复缩进并使用OrPermission组合权限:
class UserView(RetrieveUpdateDestroyAPIView): queryset = User.objects.all() serializer_class = UserSerializer http_method_names = ['patch', 'get', 'delete'] def get_permissions(self): if self.request.method == 'GET': return [IsAuthenticated(), OrPermission(IsSuperAdmin(), IsOwner(), IsAdmin())] elif self.request.method == 'DELETE': return [IsAuthenticated(), OrPermission(IsSuperAdmin(), IsAdmin())] else: return [IsAuthenticated(), OrPermission(IsSuperAdmin(), IsAdmin(), IsOwner())]
方法二:合并权限逻辑到单个类
把需要"或"逻辑的权限判断直接合并到一个自定义权限类中,减少代码复杂度:
在permissions.py中添加两个组合权限类:
class IsSuperAdminOrAdmin(BasePermission): message = "You must be super admin or admin to perform requested operation" def has_permission(self, request, view): return request.user.role in ["super_admin", "admin"] class IsSuperAdminOrAdminOrOwner(BasePermission): message = "You must be super admin, admin, or owner of the resource to perform requested operation" def has_permission(self, request, view): return request.user.role in ["super_admin", "admin"] def has_object_permission(self, request, view, obj): # 要么是超级管理员/管理员,要么是资源所有者 return self.has_permission(request, view) or obj.id == request.user.id
然后修改views.py:
class UserView(RetrieveUpdateDestroyAPIView): queryset = User.objects.all() serializer_class = UserSerializer http_method_names = ['patch', 'get', 'delete'] def get_permissions(self): if self.request.method == 'GET': return [IsAuthenticated(), IsSuperAdminOrAdminOrOwner()] elif self.request.method == 'DELETE': return [IsAuthenticated(), IsSuperAdminOrAdmin()] else: return [IsAuthenticated(), IsSuperAdminOrAdminOrOwner()]
额外注意点
- 检查
IsOwner类的拼写错误:operaton应该修正为operation。 - 若使用DRF最新版本,虽然官方开始支持用
|和&组合权限,但自定义权限类需确保运算符逻辑被正确实现,上述两种方法兼容性更强。
内容的提问来源于stack exchange,提问作者gmmic
相关产品推荐
相关产品推荐

