Custom Decorators To Check User Roles And Permissions In Django

A decorator is a function that takes another function and returns a newer, prettier version of that function.

To know more about decorators in python see here https://micropyramid.com/blog/programming-with-python-decorators/

The most common use of a decorator is the login_required, which is used in conjunction with a Django view that restricts access to authenticated users only.

from django.contrib.auth.decorators import login_required

@login_required(login_url='/dashboard/')

def index(request):

    return render(request, 'index.html')


This decorator is very useful because we don’t have to actually change anything about my view to restrict access to it.

login required takes an optional argument login_url. If a user is authenticated, it successfully executes the function, 
if not it redirects the users to URL specified in the login_url option. If we don't mention login_url option, we must define login_url in settings.py

But the login_required decorator does not check when the logged in user is active or not. We can use the "user_passes_test" decorator to write our own custom decorators

from django.contrib.auth.decorators import login_required, user_passes_test

user_login_required = user_passes_test(lambda user: user.is_active, login_url='/')

def active_user_required(view_func):
    decorated_view_func = login_required(user_login_required(view_func))
    return decorated_view_func

@active_user_required
def index(request):
    return render(request, 'index.html')

Here user_passes_test decorator returns the value of is_active, which is a boolean that designates if the user is active.
and login_url parameter, which will redirect to this URL if the user is not active. So we can use active_user_required decorator to

If you want to execute the view according to the user role, we can write decorators using model methods


def is_recruiter(self):
    if str(self.user_type) == 'Recruiter':
        return True
    else:
        return False
rec_login_required = user_passes_test(lambda u: True if u.is_recruiter else False, login_url='/')

def recruiter_login_required(view_func):
    decorated_view_func = login_required(rec_login_required(view_func), login_url='/')
    return decorated_view_func

@recruiter_login_required
def index(request):
    return render(request, 'index.html')


Here is_recruiter is a model method which checks the user role. We are using the model method in the user_passes_test decorator. If user role satisfied, then it executes the function, otherwise, it redirects the home page

If you want to execute the view according to the user permission, we can write parameterized decorators using Django permissions
We can list user permissions in the user model metaclass.

class Meta:
    permissions = (
            ('blog_view', 'can view blog posts and categories'),
            ('blog_edit', 'can edit blog category and post'),
            ("support_view", "can view tickets"),
            ("support_edit", "can edit tickets"),
            ("activity_view", "can view recruiters, applicants, data, posts"),
            ("activity_edit", "can edit data"),
        )

def has_perm(self, perm, obj=None):
    try:
        user_perm = self.user_permissions.get(codename=perm)
    except ObjectDoesNotExist:
        user_perm = False
    if user_perm:
        return True
    else:
        return False

def permission_required(*perms):
    return user_passes_test(lambda u: any(u.has_perm(perm) for perm in perms), login_url='/')

@permission_required("activity_view", "activity_edit")
def index(request):
    return render(request, 'index.html')

Here we can pass user permissions values in decorator itself, and in the permission_required, we are checking user is having particular permission or not using for loop. If user don't have permits, it redirects the home page.

    By Posted On
SENIOR DEVELOPER at MICROPYRAMID

Need any Help in your Project?Let's Talk

Latest Comments
Related Articles
Sending emails using sendgrid on heroku for a Django App Vinisha Naladala

Integrate Sendgrid API to your Heroku app to deliver simplified emails like any notification emails, user signups etc.

Continue Reading...
Django - Template language Intro Nikhila Mergu

We can write the required logics based on programming[python] syntax in models and views but, when we want to write simple logics we should follow ...

Continue Reading...
Django - Database access optimization Ashwin Kumar

Django - Database access optimization, Django Queryset is generally lazy in nature. It will not hit the database until it evaluates the query results.

Continue Reading...
open source packages

Subscribe To our news letter

Subscribe and Stay Updated about our Webinars, news and articles on Django, Python, Machine Learning, Amazon Web Services, DevOps, Salesforce, ReactJS, AngularJS, React Native.
* We don't provide your email contact details to any third parties