Creating class based view decorators using simple Django function decorators

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.

How to make AngularJS and Django play nice together

In order to make AngularJS working as I wish in my Django app, these are the settings that I’ve adopted:

1. Differentiate Angular templates symbols from Django ones:

Both Angular than Django use doble curly braces to mark variables and/or expressions ({{ myVar }}).
In order to have the full control on how and by who our templates are rendered, I redefined the Angular interpolations signs in the config() method of my client app.

$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');

2. Change the default Angular Content-type header used in POST method:

Angular defines the “Content-Type” header as “application/json” for ajax POST, but Django doesn’t understand that content properly and as result, the POST data is not an object as we expect but rather a string! So, I modified the default content type as “application/x-www-form-urlencoded” (which is the format used by jQuery and other JavaScript libraries).

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

3. Assign the CSFR token to each ajax call automagically

In Django templates we can use the tag {% csrf_token %} inside a form to print an hidden input containing the token. But when it comes to making an xhr post request, how can we pass the token in an effective and DRY manner? The answer I gave myself is to set a default http header for ajax calls containing the value of the token obtained by reading the session cookie (in this way this stuff is handle 100% by JavaScript).

$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;

Differently from points 1 and 2, this is done in the run() method, since $cookies is an Angular service and can’t be used in config() block (in that function only provider objects can be used).
In order to use $cookies we have also to import “angular-cookies.js” in addition to the base “angular.js“.

The final configuration is the following:

angular.module('myapp', ['ngCookies']).
    config([
    '$httpProvider', 
    '$interpolateProvider', 
    function($httpProvider, $interpolateProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    }]).
    run([
    '$http', 
    '$cookies', 
    function($http, $cookies) {
        $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    }]);

UPDATE:

Starting from Angular 1.2, you have also to set default headers in order to use Django helper method is_ajax() in your views:

$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';