jquery AJAX with Django

For my current project I am working on Django. But implementing ajax was little uncomfortable for me in the first place.

I wanted to use POST method but in Django there is a Cross Site Request Forgery protection(csrf) which don’t allow developers to implement it directly. The csrf protection also protect the PUT and DELETE.

So to enable the protection and work with those methods we need to go through certain steps. For forms the steps is pretty much simple, just add this {% csrf_token %} after <form>.

But to use it with jquery and ajax it’s little different. At first I tried to implement $.post() as it wasn’t working because of csrf error, I added a .js file and I was happy with it (btw, I was using Firefox until then). but then when I tried to view the application on Google Chrome it was showing our very known HTTP 403 error. And a little tracing lead me to some more detail.

jQuery.ajaxTransport.sendjquery.js:8088
jQuery.extend.ajaxjquery.js:7566
jQuery.each.jQuery.(anonymous function)jquery.js:7092
(anonymous function):8000/:198
jQuery.Callbacks.firejquery.js:1032
jQuery.Callbacks.self.fireWithjquery.js:1150
jQuery.extend.readyjquery.js:421
DOMContentLoaded

Little more reading lead me to some real fix. For ajax call, instead of using $.post() I just had to use $.ajax() and set an additional parameter.

$.ajax({
    url: "/test/test_method",
    success: function(data) {
        ...do something..
    },
    crossDomain: false
});

So basically the above code sends a GET request by default, but I was trying to use POST method. So I used the ajax csrf script from Django doc. This script sets a custom X-CSRFToken header to the value of the CSRF token on each XMLHttpRequest.

jQuery(document).ajaxSend(function(event, xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

add these three MIDDLEWARE_CLASSES

'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.csrf.CsrfResponseMiddleware',

and tada!!! it’s working on all the browsers.

Setting up django using virtualenv

Still I remember, once I was crying(!) to people to teach me virtualenv 😛 It’s actually I didn’t know that what it does, how it does and what are the benefits of using virtualenv.

Anyway, there are few and very important benefits of using virtualenv. This fantastic tool gives theh power of creating isolated Python environment. Keeps the headache of permission, version of the applications, dependencies etc.

The funnies thing about virtualenv is that, it is enormously easy to setup. YES, I mean it 🙂

sudo easy_install virtualenv

Now go to the directory where you want to create the project and type

virtualenv --no-site-packages vdjango

now install django

./vdjango/bin/easy_install django

Start a django project

./vdjango/bin/django-admin.py startproject myapp

now to the project directory and run the project.

../vdjango/bin/python manage.py runserver 0.0.0.0:8000

tada!!!!