33

view.py

@login_required
@permission_required('is_superuser')
def score_reset(request):
   pass

url.py

url(r'^score-reset/$', score_reset, name='score-reset'),    

I have the following code and to my surprise I still hit the function, despite being logged in with a non superuser. I was expecting to get a permission denied.

What am I missing?

Houman
  • 64,245
  • 87
  • 278
  • 460

6 Answers6

63

is_superuser isn't a permission, it's an attribute on the user model. Django already has another decorator you can make use of called user_passes_test to perform this check:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda u: u.is_superuser)
def score_reset(self,...):
    ...
Community
  • 1
  • 1
Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • btw, I'm not marking this as a duplicate as neither answer I've linked to mention that `user_passes_test` is an existing django decorator as well as the fact that `is_superuser` isn't a permission – Timmy O'Mahony Apr 14 '13 at 11:49
  • 2
    The question asks for restricting to superuser only. The example code should be @user_passes_test(lambda u: u.is_superuser) – mhost Apr 29 '15 at 13:59
  • 1
    Using `user_passes_test` [the above snippet] does the work.But you may want to consider that this is will redirect to login page for all non-super users, even if they have already logged in.You may want to write your own decorator to get the job done. – ALLSYED Sep 12 '16 at 09:29
7

Above answers seems to be for very early versions of django. They are bit complicated than for the more later version

for django 1.11 here is a bit similar but simpler strategy.

views.py

from django.contrib.auth.decorators import login_required

@login_required
def some_view(request):
if request.user.is_superuser:
    //allow access only to superuser
    return render(request, 'app/template1.html', args)
else:
    //allow access only to user
    return render(request, 'app/template2.html', args)
Nitish Kumar Pal
  • 2,738
  • 3
  • 18
  • 23
4

Make use of Django's UserPassesTestMixin

Create a custom mixin SuperuserRequiredMixin

#mixins.py
from django.contrib.auth.mixins import UserPassesTestMixin

class SuperuserRequiredMixin(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.is_superuser

Usage

class SomeSuperUserOnlyView(SuperuserRequiredMixin, ListView):
    form_class = ExamForm
    template_name = 'exam/newexam.html'
Sumithran
  • 6,217
  • 4
  • 40
  • 54
2

@user_passes_test is not an elegant solution if you want to perform this check on many views. You can easily write your own decorathor having for example @staff_member_require.

Here you can see one of the possible solutions.

koradon
  • 91
  • 1
  • 3
1

You can use the user passes test decorator to restrict access any way you want. Here is a restriction based on user email example:

from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    x = False
    if user.email == 'anyemailhere':
        x = True
    return x

# Create your views here.
@user_passes_test(email_check)
def dash_index(request):
    ...

More here https://docs.djangoproject.com/en/2.1/topics/auth/default/#the-permission-required-decorator

Josh
  • 2,122
  • 1
  • 21
  • 28
0

SuperuserRequiredMixin

Another permission-based mixin. This is specifically for requiring a user to be a superuser. Comes in handy for tools that only privileged users should have access to.

First install: pip install django-braces

views.py

from braces.views import LoginRequiredMixin, SuperuserRequiredMixin


class SomeSuperuserView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
    template_name = "path/to/template.html"