How to use permission_required decorators on django class-based views How to use permission_required decorators on django class-based views django django

How to use permission_required decorators on django class-based views


There are a few strategies listed in the CBV docs:

Decorate the view when you instantiate it in your urls.py (docs)

urlpatterns = [    path('view/',login_required(ViewSpaceIndex.as_view(..)),    ...]

The decorator is applied on a per-instance basis, so you can add it or remove it in different urls.py routes as needed.

Decorate your class so every instance of your view is wrapped (docs)

There's two ways to do this:

  1. Apply method_decorator to your CBV dispatch method e.g.,

     from django.utils.decorators import method_decorator @method_decorator(login_required, name='dispatch') class ViewSpaceIndex(TemplateView):     template_name = 'secret.html'

If you're using Django < 1.9 (which you shouldn't, it's no longer supported) you can't use method_decorator on the class, so you have to override the dispatch method manually:

    class ViewSpaceIndex(TemplateView):        @method_decorator(login_required)        def dispatch(self, *args, **kwargs):            return super(ViewSpaceIndex, self).dispatch(*args, **kwargs)
  1. Use a mixin like django.contrib.auth.mixins.LoginRequiredMixin outlined well in the other answers here:

     from django.contrib.auth.mixins import LoginRequiredMixin class MyView(LoginRequiredMixin, View):     login_url = '/login/'     redirect_field_name = 'redirect_to'

Make sure you place the mixin class first in the inheritance list (so Python's Method Resolution Order algorithm picks the Right Thing).

The reason you're getting a TypeError is explained in the docs:

Note:method_decorator passes *args and **kwargs as parameters to the decorated method on the class. If your method does not accept a compatible set of parameters it will raise a TypeError exception.


Here is my approach, I create a mixin that is protected (this is kept in my mixin library):

from django.contrib.auth.decorators import login_requiredfrom django.utils.decorators import method_decoratorclass LoginRequiredMixin(object):    @method_decorator(login_required)    def dispatch(self, request, *args, **kwargs):        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

Whenever you want a view to be protected you just add the appropriate mixin:

class SomeProtectedViewView(LoginRequiredMixin, TemplateView):    template_name = 'index.html'

Just make sure that your mixin is first.

Update: I posted this in way back in 2011, starting with version 1.9 Django now includes this and other useful mixins (AccessMixin, PermissionRequiredMixin, UserPassesTestMixin) as standard!


Here's an alternative using class based decorators:

from django.utils.decorators import method_decoratordef class_view_decorator(function_decorator):    """Convert a function based decorator into a class based decorator usable    on class based Views.    Can't subclass the `View` as it breaks inheritance (super in particular),    so we monkey-patch instead.    """    def simple_decorator(View):        View.dispatch = method_decorator(function_decorator)(View.dispatch)        return View    return simple_decorator

This can then be used simply like this:

@class_view_decorator(login_required)class MyView(View):    # this view now decorated