首页 > 解决方案 > 将变量传递给 DRF 中的权限类会出错

问题描述

我正在尝试在项目的许多应用程序中使用以下权限类,唯一需要更改的是从中检查用户数据的模型类。

权限类:

class IsAuthorOrForbidden(permissions.BasePermission):
"""
Check if the requesting user the author or not
"""
def __init__(self, modelClass):
    self.modelClass = modelClass

def has_permission(self, request, view):
    # get the needed model instance or 404 if not available
    instance = get_object_or_404(self.modelClass, pk=view.kwargs['pk'])
    # Check if the requesting user is the author
    if instance.user == request.user:
        return True
    return False

视图类中的权限类:

class TextNoteGenerateShareKeyAPIView(generics.UpdateAPIView):
"""
Generate a new text note share key
"""
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,
                      IsAuthorOrForbidden(modelClass=TextNote))
...

当我运行测试时,我收到此错误:

return [permission() for permission in self.permission_classes] TypeError: 'IsAuthorOrForbidden' object is not callable

是否可以这样做,或者我应该在项目中的每个应用程序中编写这个权限类?

标签: pythondjangodjango-rest-framework

解决方案


您可以使用对象级权限

class IsAuthorOrForbidden(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        return obj.user == request.user

并将其添加到视图中,如下所示:

permission_classes = (IsAuthenticated,
              IsAuthorOrForbidden)

错误发生原因的说明

要理解错误,需要查看get_permissionsGitHub 源代码中方法的实现:

#copy pasted from GitHub
def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    """
    return [permission() for permission in self.permission_classes]

这里是从 中列出对象self.permission_classes,意思permission_classes是假设有类,而不是对象。

您正在向IsAuthorOrForbidden权限类添加对象,您需要在其中添加类。如果你想覆盖,那么应该在这里完成:

class TextNoteGenerateShareKeyAPIView(generics.UpdateAPIView):

    def get_permissions(self):
        return [IsAuthenticated(), IsAuthorOrForbidden(modelClass=TextNote)]

但这是一个骇人听闻的解决方案,其中原始答案中的解决方案是在 DRF 中实施的正确方法。


推荐阅读