has_object_permission 未调用
has_object_permission not called
我查看了关于同一主题的类似问题,我认为我遵守了为 has_object_permission
指定的所有规则。
这是我的设置。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
'users.permissions.CanAccessData', # this is my custom class
],
...
}
这是我的许可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
被调用了。
列表视图不调用has_object_permission
。 documentation 表示如下:
Also note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you'll need to filter the queryset separately. See the filtering documentation for more details.
我运行陷入同样的问题。 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)
除了预取相关对象并单独检查权限外,这基本上是原始实现。
但是,从某种意义上说,这可能是 DRY,因为您不必重写 get_queryset()
方法来以某种方式重新发明您的 has_object_permission
逻辑。但它也很慢,因为它获取对象两次。不过,您可以通过使用已经预取的对象而不是过滤查询集来改善这种情况。
has_object_permission 方法只有在视图级 has_permission 检查已经通过时才会被调用。
看看这个真实世界的例子
奥林匹亚项目 github (https://github.com/mozilla/addons-server/blob/master/src/olympia/ratings/permissions.py)
class CanDeleteRatingPermission(BasePermission):
"""A DRF permission class wrapping user_can_delete_rating()."""
def has_permission(self, request, view):
return request.user.is_authenticated
def has_object_permission(self, request, view, obj):
return user_can_delete_rating(request, obj)
当使用此权限class时,如果has_permission通过则has_object_permission( user_can_delete_rating() 函数 ) 被调用。
我查看了关于同一主题的类似问题,我认为我遵守了为 has_object_permission
指定的所有规则。
这是我的设置。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
'users.permissions.CanAccessData', # this is my custom class
],
...
}
这是我的许可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
被调用了。
列表视图不调用has_object_permission
。 documentation 表示如下:
Also note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you'll need to filter the queryset separately. See the filtering documentation for more details.
我运行陷入同样的问题。 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)
除了预取相关对象并单独检查权限外,这基本上是原始实现。
但是,从某种意义上说,这可能是 DRY,因为您不必重写 get_queryset()
方法来以某种方式重新发明您的 has_object_permission
逻辑。但它也很慢,因为它获取对象两次。不过,您可以通过使用已经预取的对象而不是过滤查询集来改善这种情况。
has_object_permission 方法只有在视图级 has_permission 检查已经通过时才会被调用。
看看这个真实世界的例子
奥林匹亚项目 github (https://github.com/mozilla/addons-server/blob/master/src/olympia/ratings/permissions.py)
class CanDeleteRatingPermission(BasePermission):
"""A DRF permission class wrapping user_can_delete_rating()."""
def has_permission(self, request, view):
return request.user.is_authenticated
def has_object_permission(self, request, view, obj):
return user_can_delete_rating(request, obj)
当使用此权限class时,如果has_permission通过则has_object_permission( user_can_delete_rating() 函数 ) 被调用。