DRF-未调用has_object_permission

时间:2019-02-20 09:55:03

标签: django django-rest-framework django-permissions

因此,我浏览了关于同一主题的类似问题,并且 我认为 我遵循为has_object_permission指定的所有规则。

这就是我的设置。

REST_FRAMEWORK = {

    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
        'users.permissions.CanAccessData', # this is my custom class
    ],

    .  
    .
    .
}

这是我的权限等级

class CanAccessData(permissions.BasePermission):
    message = 'You do not have permission to perform this action.'

    def has_permission(self, request, view):
        print "has_permission`"
        return True

    def has_object_permission(self, request, view, obj):
        print "has_object_permission"
        return False

这是我的视图结构:

class CompleteList(generics.ListCreateAPIView):
    permission_classes = (CanAccessData,)
    serializer_class = SomeSerializer
    model = Some
    filter_backends = (filters.OrderingFilter, filters.SearchFilter)
    ordering_fields = (tuple of Some fields)
    search_fields = ordering_fields
    ordering = ('-create_date')

仍然,has_object_permission未被调用,has_permission被调用。

谢谢。

2 个答案:

答案 0 :(得分:0)

列表视图未调用has_object_permissiondocumentation说:

  

还请注意,通用视图将仅检查对象级权限以获取检索单个模型实例的视图。如果需要列表视图的对象级过滤,则需要分别过滤查询集。有关更多详细信息,请参见过滤文档。

答案 1 :(得分:0)

我遇到了同样的问题。列出对象时,永远不会调用has_object_permission函数。

即使以下方法不是最有效的解决方案,您也可以按如下所示在视图中覆盖list方法,这就是我为我解决的方法:

from typing import List
import rest_framework.permissions as drf_permissions

def list(self, request, *args, **kwargs):

    # base query set
    queryset: QuerySet = self.filter_queryset(self.get_queryset())

    # check object permissions for each object individually
    valid_pks: List[int] = []  # # storage for keys of valid objects
    permissions: List[drf_permissions.BasePermission] = self.get_permissions()
    for obj in queryset:
        for permission in permissions:
            if permission.has_object_permission(request, self, obj):
                valid_pks.append(obj.pk)

    # remove not valid objects from the queryset
    queryset = queryset.filter(pk__in=valid_pks)

    # ... business as usual (original code)
    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_queryset()方法以某种方式重新发明has_object_permission逻辑的意义上,这可能是DRY。但是它也很慢,因为它两次获取对象。您可以通过使用已经预取的对象而不是过滤查询集来改善这种情况。