June 5th, 2012

Django and AJAX: jQuery

Tutorial for: Django

This tutorial will focus on using Django with pure jQuery, and making use of Class-based views. This tutorial will introduce something I like to call a dual-view. A single view with multiple output formats.

Hello, and welcome to the second tutorial in my Django and AJAX tutorial set. In this tutorial, I will focus on using Django Class-based views to generate content depending on what the client is requesting. As everyone who has done AJAX development knows, most frameworks send a special header to the server when the request is an AJAX request. In this custom view, we will explore using an extendable class-based view to dispatch the output depending on this specific header. This means, that this class can be used with most popular JavaScript frameworks, but in this tutorial, we will focus on jQuery.

This tutorial requires nothing more than Django itself. You will need version 1.3 or higher, because Class-based views were properly introduced and supported from this version on. Technically in previous versions you can create Class-based views, but in Django 1.3 and up, they made developing Class-based views more of a pleasure to work with. This tutorial will be compatible with any Django version from 1.3 and higher, and thus uses no 1.4 or higher specific features. I know that some users may still run an older version of Django for compatibility reasons, as some apps have still not been updated to work with newer versions of Django, which completely remove function-based generic views.

Most AJAX frameworks send an HTTP Header labeled X-Requested-With, and this example will use this header to determine what to respond back to the client. If your framework of choice does not set this header, there should be an option to add additional header values when sending the request.

This code is partly taken from the official Django documentation, however it has been modified to work. Using the Django example as is will result in a 500 error due to simplejson being unable to convert over a Model object.

from django.http import HttpResponse
from django.utils import simplejson
from django.views.generic.detail import BaseDetailView, \
    SingleObjectTemplateResponseMixin

class JSONResponseMixin(object):
    def render_to_response(self, context):
        return self.get_json_response(self.convert_context_to_json(context))
    def get_json_response(self, content, **httpresponse_kwargs):
        return HttpResponse(content, content_type='application/json', **httpresponse_kwargs)
    def convert_context_to_json(self, context):
        return simplejson.dumps(context)

class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
    def render_to_response(self, context):
        if self.request.is_ajax():
            obj = context['object'].as_dict()
            return JSONResponseMixin.render_to_response(self, obj)
        else:
            return SingleObjectTemplateResponseMixin.render_to_response(self, context)

The main change from the example in the Django documentation is that when it passes the context over to JSONResponseMixin, it passes a dictionary representation of the model. Here is the example model this example will be working with:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=80)
    birthday = models.DateField()
    def __unicode__(self):
        return u"%s was born in %s" % (self.name, self.birthday.strftime("%B of %Y"))
    def as_dict(self):
        return {'name':self.name, 'birthday':self.birthday.strftime("%B of %Y")}

A fairly simple example, the __unicode__ function is going to be used in the template to demonstrate fetching the same without AJAX. This also shows the as_dict function, which is customizable and generates a simple dictionary of the model. If anybody knows of an easier method to generate a dictionary from a model suitable for JSONifying, please let me know. Next, I will show the template code being used:

<html>
<head>
<title>jQuery test page</title>
<script type="text/javascript" src="/js/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
function send_request(){
  $.get(location.href, function(data){
    $("#idName").html(data.name);
    $("#idBirthday").html(data.birthday);
  });
}
</script>
</head>
<body>
Object in template called without AJAX: {{object}}<hr/>
<input type="button" onclick="send_request();" value="Request this page with AJAX" /><br/>
<b>Name via AJAX:</b><span id="idName"></span><br/>
<b>Birthday via AJAX:</b><span id="idBirthday"></span><br/>
</body>
</html>

A very very simple template. In the AJAX calling component, the template will call itself, as seen by the location.href variable being used. This template will render both the object using non-AJAX, and render it using AJAX provided by the HybridDetailView. Finally the URL glue:

from ajaxsite.jquery.models import Person
from ajaxsite.jquery.views import HybridDetailView
from django.conf.urls.defaults import patterns

urlpatterns = patterns('',
    (r'^(?P<pk>\d)$', HybridDetailView.as_view(model=Person)),
)

Very simple and should be straightforward. I wrote the example, as I was writing this article, and confirmed that it does work. There are other ways to implement AJAX using jQuery and Django, this method may be overkill for some applications, but it does show how to use Class-based views to implement the entire workflow. If you have any questions regarding this tutorial, please post comments in the section below. The next tutorial will focus on using Dajax, which allows you to code your entire AJAX site in pure Python and HTML, with minimal JavaScript.

Dec. 5, 2012, 8:16 a.m. - Brad

Great post this was very helpful. I was looking for a way to encode all of the object's data into a json request and you offered a solution to that. Thanks

About Me

My Photo
Names Kevin, hugely into UNIX technologies, not just Linux. I've dabbled with the demons, played with the Sun, and now with the Penguins.




Kevin Veroneau Consulting Services
Do you require the services of a Django contractor? Do you need both a website and hosting services? Perhaps I can help.

This Month

If you like what you read, please consider donating to help with hosting costs, and to fund future books to review.

Python Powered | © 2012-2014 Kevin Veroneau