Просмотрел похожие вопросы по той же теме и я думаю соблюдаю все правила указанные для 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 звонят.





has_object_permission не вызывается для просмотра списка. документация говорит следующее:
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.
Просто чтобы продолжить здесь, я считаю, что для фильтрации набора запросов вы бы реализовали: def get_queryset(self): в представлении. Я новичок в DRF, поэтому примите это во внимание, доверяя моему ответу.
Если вы используете представление списка, то как вы можете вызвать этот метод?
Я столкнулся с той же проблемой. Функция 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. Но также он медленный, так как извлекает объекты дважды. Однако вы можете улучшить эту ситуацию, работая с уже предварительно выбранными объектами вместо фильтрации набора запросов.
Метод 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)
при использовании этого класса разрешений, если передается has_permission, вызывается has_object_permission (функция user_can_delete_rating()).
Спасибо. Я упустил это из виду. Любая другая идея о том, как вообще фильтровать набор запросов?