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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s