kaiser
kaiser

Reputation: 135

Make PermissionRequiredMixin also check for object level permission

I am using Django Guardian to have object-level permission along with global permissions. Some of the users have a group with global permissions, and some have object-level permissions. With this, I seem to need to modify the PermissionRequiredMixin to check also for the object-level permission.

views.py

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

This one works if the user has global permission but if the user is under a group with object-level permission, it won't. With guardian, to check for object-level permission, you also have to pass the object instance.

example:

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

And on PermissionRequiredMixin, the checking goes only like this, self.request.user.has_perms(perms)

So if the user has a group with permission of view_mainpage of a specific object, how can I check it too? By the way, all my permissions are of the same content_type. Is there any way I can execute this? Like I have to pass the object instance to PermissionRequiredMixin if the user is under an object-level group and None if the user is under a global group.

Upvotes: 4

Views: 1123

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476547

You can implement such mixin yourself with:

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

Then you can mix this mixin into a view, for example:

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

This will work for all Views that usee the SingleObjectMixin [Django-doc] such as a DetailView, UpdateView, and the DeleteView.

Upvotes: 5

Related Questions