Сделать PermissionRequiredMixin также проверяющим разрешение на уровне объекта

Я использую Django Guardian, чтобы иметь разрешения на уровне объекта наряду с глобальными разрешениями. Некоторые из пользователей имеют группу с глобальными разрешениями, а некоторые имеют разрешения на уровне объекта. В связи с этим, мне кажется, что нужно изменить PermissionRequiredMixin, чтобы проверить также разрешение на уровне объекта.

views.py

class MainPageView(PermissionRequiredMixin, TemplateView):
    permission_required = "app.view_mainpage"
    template_name = "web/mainpage.html"

Этот вариант работает, если пользователь имеет глобальные права, но если пользователь находится под группой с правами объектного уровня, то он не сработает. В guardian, чтобы проверить разрешение на уровне объекта, необходимо также передать экземпляр объекта.

пример:

self.request.user.has_perm('view_mainpage', obj)

На PermissionRequiredMixin проверка проходит только так, self.request.user.has_perms(perms)

Итак, если у пользователя есть группа с разрешением view_mainpage определенного объекта, как я могу проверить и его? Кстати, все мои разрешения имеют одинаковое значение content_type. Могу ли я каким-либо образом выполнить это? Например, я должен передать экземпляр объекта в PermissionRequiredMixin, если пользователь находится под группой объектного уровня, и None, если пользователь находится под глобальной группой.

Вы можете реализовать такой миксин самостоятельно с помощью:

from django.core.exceptions import PermissionDenied

class ObjectPermissionRequiredMixin:
    object_permission_required = None
    object_permission_denied_message = None

    def has_object_permission(self, obj):
        return self.request.user.has_perm(self.object_permission_required, obj)

    def get_object_permission_denied_message(self):
        return self.object_permission_denied_message

    def handle_no_object_permission(self):
        raise PermissionDenied(self.get_object_permission_denied_message())

    def get_object(self, *args, **kwargs):
        obj = super().get_object(*args, **kwargs)
        if not self.has_object_permission(obj)
            return self.handle_no_object_permission()
        return obj

Затем вы можете подмешать этот миксин в представление, например:

class MyUpdateView(ObjectPermissionRequiredMixin, UpdateView):
    model = MyModel
    object_permission_required = 'app.update_my_model'
    object_permission_denied_message = 'You can not edit this object'

Это будет работать для всех View, которые используют SingleObjectMixin [Django-doc], таких как DetailView, UpdateView и DeleteView.

Вернуться на верх