Has_object_permission не вызывается

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
3 362
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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.

Спасибо. Я упустил это из виду. Любая другая идея о том, как вообще фильтровать набор запросов?

Kishor Pawar 20.02.2019 11:21

Просто чтобы продолжить здесь, я считаю, что для фильтрации набора запросов вы бы реализовали: def get_queryset(self): в представлении. Я новичок в DRF, поэтому примите это во внимание, доверяя моему ответу.

Oded 02.05.2019 22:07

Если вы используете представление списка, то как вы можете вызвать этот метод?

Sabito 錆兎 06.09.2021 06:02

Я столкнулся с той же проблемой. Функция 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()).

Другие вопросы по теме