What is a Decorator?

A decorator is the name of one of the most popular design patterns used nowadays, many times we use it without knowing that we are using a design pattern. And what’s so special about this pattern? As we can read at  Python Wiki using It is a way of apparently modifying an object’s behavior, by enclosing it inside a decorating object with a similar interface. You can get more information about Pattern Design here.

Why I should use in my web application?

Decorators dynamically alter the functionality of a function, method or class without having to make subclasses or change the source code of the decorated class. Thanks to this our code will be more cleaner, more readable, maintainable (Which is no small thing), and reduce the boilerplate code allowing us to add functionality to multiple classes using a single method.

A good example of the importance and easy of use of these decorators can be seen in the decorator @login_required that provides , and that you probably used if you have some experience with our favorite framework. It’s just a piece of code where we check if the user is not authenticated the user is redirected to the login url.

The way that the decorators as used is the following:

from django.contrib.auth.decorators import login_required

def my_view(request)

Each time that a user try to access to my_view, the code inside login_required will be ejecuted.

Some of our favorite decorators

In this section we will show you some of the decorators that we think are most useful or that we have ever used with positive results, keep in mind that many of these can be customized to suit your needs. For this post we will use the original decorators with their font.

Group Required

Sometimes we need to protect some views, to allow a certain group of users to access it. Instead of checking within it if the user belongs to that group/s, we can use the following decorator

from django.contrib.auth.decorators import user_passes_test

def group_required(*group_names):
   """Requires user membership in at least one of the groups passed in."""

   def in_groups(u):
       if u.is_authenticated():
           if bool(u.groups.filter(name__in=group_names)) | u.is_superuser:
               return True
       return False
   return user_passes_test(in_groups)

# The way to use this decorator is:
@group_required(‘admins’, ‘seller’)
def my_view(request, pk)

You can get more information about it here

Anonymous required

This decorator is based on the decorator login_required of Django, but looks for the opposite case, that the user is anonymous, otherwise the user is redirected to the website defined in our settings.py and can be useful when we want to protect logged user views, such as the login or registration view

def anonymous_required(function=None, redirect_url=None):

   if not redirect_url:
       redirect_url = settings.LOGIN_REDIRECT_URL

   actual_decorator = user_passes_test(
       lambda u: u.is_anonymous(),

   if function:
       return actual_decorator(function)
   return actual_decorator

# The way to use this decorator is:
def my_view(request, pk)

You can get more information about it here

Superuser required

This is the same case as when we want to allow certain groups access to a view, but in this case only super users can visit it.

from django.core.exceptions import PermissionDenied

def superuser_only(function):
  """Limit view to superusers only."""

   def _inner(request, *args, **kwargs):
       if not request.user.is_superuser:
           raise PermissionDenied           
       return function(request, *args, **kwargs)
   return _inner

# The way to use this decorator is:
def my_view(request):

You can get more information about it here

Ajax required

This decorator check if the request is an AJAX request, useful decorator when we are working with Javascript frameworks as jQuery and a good way to try to secure our application

from django.http import HttpResponseBadRequest

def ajax_required(f):
   AJAX request required decorator
   use it in your views:

   def my_view(request):


   def wrap(request, *args, **kwargs):
       if not request.is_ajax():
           return HttpResponseBadRequest()
       return f(request, *args, **kwargs)

   return wrap

# The way to use this decorator is:
def my_view(request):

You can get more information about it here

Time it

This decorator is very helpful if you need to improve the response time of one of then our views or if you just want to know how long it takes to run.

def timeit(method):

   def timed(*args, **kw):
       ts = time.time()
       result = method(*args, **kw)
       te = time.time()
       print('%r (%r, %r) %2.2f sec' % (method.__name__, args, kw, te - ts))
       return result

   return timed

# The way to use this decorator is:
def my_view(request):

You can get more information about it here

Custom Functionality

The next decorator is just an example about how you can check some permissions or some checks in a easy way and 100% customizable.

Imagine you have a blog, shop, forum…. Where users need to have a number of points in order to write a review, it would be a good way to avoid SPAM for example. We’ll create a decorator to check that the user is logged in and has more than 10 points, so you could write a review, otherwise we’ll raise a Forbidden

from django.http import HttpResponseForbidden

logger = logging.getLogger(__name__)

def user_can_write_a_review(func):
   """View decorator that checks a user is allowed to write a review, in negative case the decorator return Forbidden"""

   def wrapper(request, *args, **kwargs):
       if request.user.is_authenticated() and request.user.points < 10:
           logger.warning('The {} user has tried to write a review, but does not have enough points to do so'.format( request.user.pk))
           return HttpResponseForbidden()

       return func(request, *args, **kwargs)

   return wrapper

You can get more information about it asking myself at [email protected] or via twitter @pypiglesias.  I really hope you found the post interesting or at least curious. From BeDjango we would like to encourage you to share your decorators, ideas or questions as well as interesting topics for future posts

Source link


Please enter your comment!
Please enter your name here