Rudra Mutalik
Rudra Mutalik

Reputation: 370

django PermissionRequiredMixin permission_required not working

Views.py

class templateList(PermissionRequiredMixin, TemplateView):
    permission_required = 'accounts.template_all'

    def get(self, request, *args, **kwargs):
        #view logic
        print(self.request.user.has_perms('accounts.template_all'))
        return render(request, template_name, context)

accounts/models.py

class User(AbstractBaseUser, PermissionsMixin):
    # some fields here
    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

        permissions = (
            ("template_all", "access to all templates"),
        )

ViewName.___mro____

(<class 'template.views.templateList'>, <class 'django.contrib.auth.mixins.PermissionRequiredMixin'>, <class 'django.contrib.auth.mixins.AccessMixin'>, <class 'django.views.generic.base.TemplateView'>, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.base.ContextMixin'>, <class 'django.views.generic.base.View'>, <class 'object'>)

self.request.user.has_perms('accounts.template_all') in views.py returns the correct boolean value, however, self.has_permission() returns True every time. permission_required has no effect, and the user is still able to see the page even when the print returns false. self.get_permission_required alos returns the correct value. Help appreciated.

Upvotes: 2

Views: 8804

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

In short: the PermissionRequiredMixin baseclass should be placed before the TemplateView baseclass, such that the MRO (Method Resolution Order) is correct, and dispatch points to the override of the PermissionRequiredMixin.

A PermissionRequiredMixin patches the dispatch(..) method (well it adds an extra check that looks if the user has the proper permissions). Here however you have placed the subclasses in an order that results in the fact that the dispatch(..) function is the one from the View class.

Indeed, if we take a look at the MRO, we see:

>>> ViewName.__mro__
(<class 'ViewName'>, <class 'django.views.generic.base.TemplateView'>, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.base.ContextMixin'>, <class 'django.views.generic.base.View'>, <class 'django.contrib.auth.mixins.PermissionRequiredMixin'>, <class 'django.contrib.auth.mixins.AccessMixin'>, <class 'object'>)

and if we take a look at the method that is called when we call .dispatch(..), we see:

>>> ViewName.dispatch
<function View.dispatch at 0x7f169e8f6620>

In order to let the mixin override the original .dispatch(..) function, we need to put it first in the base classes, like:

# PermissionRequiredMixin is put before TemplateView

class ViewName(PermissionRequiredMixin, TemplateView):
    permission_required = 'accounts.action_all'
    # ...

We then see that:

>>> ViewName.__mro__
(<class 'ViewName'>, <class 'django.contrib.auth.mixins.PermissionRequiredMixin'>, <class 'django.contrib.auth.mixins.AccessMixin'>, <class 'django.views.generic.base.TemplateView'>, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.base.ContextMixin'>, <class 'django.views.generic.base.View'>, <class 'object'>)
>>> ViewName.dispatch
<function PermissionRequiredMixin.dispatch at 0x7f168b41d620>

Upvotes: 7

Related Questions