如何为基于类的 APIView 实现 DjangoModelPermissions?它抛出查询集错误

man*_*ari 0 python django django-models django-views django-rest-framework

场景:我有组和权限,权限与组关联,并且该组与用户关联。现在我尝试通过DjangoModelPermissions实现视图的权限

这对于实现查询集的以下代码行效果很好;

class UpdateCampaignView(generics.UpdateAPIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [DjangoModelPermissions]

    queryset = Campaign.objects.all()
    serializer_class = UpdateCampaignSerializer

    def get_object(self):
        campaign_id = self.request.data.get("id")
        return Campaign.objects.get(id =campaign_id)
Run Code Online (Sandbox Code Playgroud)

但我想将其实现为基于类的 APIView,无需使用 queryset 关键字,如下所示:

class RetrieveCampaignView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [DjangoModelPermissions] #this is what i want to do
    
    def get(self, request, *args, **kwargs):
        try:
            campaign = Campaign.objects.get(id = request.data.get("id"))
            searializer = GetCampaignSerializer(campaign)
            return Response({"status":True , "payload":searializer.data})
        
        except:
            return Response({"status":False}, status=status.HTTP_404_NOT_FOUND)
Run Code Online (Sandbox Code Playgroud)

但这给出了以下错误:

djangorest框架错误无法在未设置.queryset或没有.get_queryset()方法的视图上应用DjangoModelPermissions

ued*_*mir 6

课堂上有讲解DjangoModelPermissions

\n
\n

此权限只能应用于提供.queryset属性的视图类。 \n

\n
\n

因此,您不能在没有queryset属性的情况下使用此权限类。您可以创建自己的权限类以与 一起使用,而不是使用它APIView。例如你有permissions.py喜欢;

\n
from rest_framework.permissions import BasePermission\n\n\nclass MyPermission(BasePermission):\n    message = "You do not have permission to retrive object"\n\n    def has_permission(self, request, view):\n        if request.user.has_perm("app.view_yourmodel"):\n            return True\n        return False\n
Run Code Online (Sandbox Code Playgroud)\n

并将此自定义权限类指定给您的视图;

\n
from rest_framework.permissions import IsAuthenticated\n\nfrom app.permissions import MyPermission\n\n\nclass RetrieveCampaignView(APIView):\n    authentication_classes = [TokenAuthentication]\n    permission_classes = [IsAuthenticated, MyPermission]\n\n    ...\n
Run Code Online (Sandbox Code Playgroud)\n

最后,你应该从 django 模型中找到你自己的权限代码Permission,并将其更改为app.view_yourmodel. 来自文档

\n
\n

当 django.contrib.auth 在 INSTALLED_APPS 设置中列出时,它将确保为以下之一中定义的每个 Django 模型创建四个默认权限 \xe2\x80\x93 添加、更改、删​​除和查看 \xe2\x80\x93您安装的应用程序。

\n
\n

所以,如果你想找到你的模型权限;

\n
from django.contrib.auth.models import Permission\nfrom django.contrib.contenttypes.models import ContentType\n\nfrom app.models import Campaign\n\n\ncontent_type = ContentType.objects.get_for_model(Campaign)\nperms = Permission.objects.filter(content_type=content_type)\nprint([perm.codename for perm in perms])\n
Run Code Online (Sandbox Code Playgroud)\n

您可以访问文档以获取有关自定义权限的更多信息

\n

根据评论更新答案

\n
\n

如何使 ==> request.user.has_perm(\'app.view_yourmodel\') 动态\nfor code_name 否则我需要为每个 has_perm 参数(即 code_name)传递一大堆 MyPermission for\n每个视图。

\n
\n

如果您想使用更通用的自定义权限结构,那么您可以实现自己的逻辑。例如,让我们创建自己的视图属性,perm_slug = "app.model_name"因为我们需要知道用户尝试执行操作的模型。您必须为要使用的所有视图正确实现此属性MyPermission,然后在权限类中解析此属性,获取相关的权限密钥并检查请求用户是否具有此权限密钥。

\n
class MyPermission(BasePermission):\n    message = "You do not have permission to perform action"\n    permission_map = {\n        "GET": "{app_label}.view_{model_name}",\n        "POST": "{app_label}.add_{model_name}",\n        "PUT": "{app_label}.change_{model_name}",\n        "PATCH": "{app_label}.change_{model_name}",\n        "DELETE": "{app_label}.delete_{model_name}",\n    }\n\n    def _get_permission(self, method, perm_slug):\n        app, model = perm_slug.split(".")\n        if method not in self.permission_map:\n            raise MethodNotAllowed(method)\n        perm = self.permission_map.get(method).format(app_label=app, model_name=model)\n        return perm\n\n    def has_permission(self, request, view):\n        perm = self._get_permission(\n            method=request.method, perm_slug=view.perm_slug\n        )\n        if request.user.has_perm(perm):\n            return True\n        return False\n
Run Code Online (Sandbox Code Playgroud)\n

并修改您的视图,例如;

\n
class RetrieveCampaignView(APIView):\n    authentication_classes = [TokenAuthentication]\n    permission_classes = [IsAuthenticated, MyPermission]\n    perm_slug = "app.campaign"\n\n    ...\n
Run Code Online (Sandbox Code Playgroud)\n