I love decorators because they allow to extend class/functions capabilities and to be be added and removed easily. Django offers a set of decorators but unfortunely they are designed for functions or class methods only and instead I want to add them to the whole class in order to avoid to override the orignal method just to add the decorator annotation above it. Fortunately wrapping the simple Django decorators in order to use them against classes (basically View classes) is quite simple and I’m gonna show you what I done.
For example let’s consider we have a view that require a POST method. If we use a simple function view we can write the following:
@require_POST def myView(request): return HttpResponse('hello world!')
but, if we use class views (and we should!), we are forced to write:
class MyView(SomeKindOfParentClassView): # ...imagine several methods here @require_POST def dispatch(self, request, *args, **kwargs): return HttpResponse('hello world!')
wouldn’t be cleaner and more elegant instead to simply write the following?
@require_POST class MyView(SomeKindOfParentClassView): # ...imagine several methods here
…and this is the class decorator implementation:
from django.views.decorators.http import require_POST as post_only def require_POST(View): View.dispatch = method_decorator(post_only)(View.dispatch) return View
Basically I redefined the class method and returned the class itself.
This was really simple since the concrete implementation of the decorator has been added using the existend Django decorators… but what if we want to create a custom decorator? For example in my app I created a decorator that enable access to a view only if it’s requested via ajax, this is how I implemented it:
def require_AJAX(SomeKindOfParentClassView): def ajaxOnly(function): def wrap(request, *args, **kwargs): if not request.is_ajax(): return HttpResponseForbidden() return function(request, *args, **kwargs) return wrap View.dispatch = method_decorator(ajaxOnly)(View.dispatch) return View
And the decorated view looks like this:
@require_POST @require_AJAX class MyView(SomeKindOfParentClassView): # ...imagine several methods here
As you can see that annotations are really readable, immediate and self-describing.