I was wondering how requests via AJAX can be implemented into Django framework. So I wrote a small application and hooked it into an existing Django project for testing purposes. The application has two models, Employee and Project, and two methods. The first method fetches data from the project and employee tables and renders that data onto a template. The second method takes care of the AJAX request and returns a JSON string. There is javaScript code embedded on the template itself, which is responsible for the AJAX requests and manipulating DOM on a successful response.

My project structure looks like this:

ajax_tut_project_structure

The models:

from django.db import models

class Employee(models.Model):
    name = models.CharField(max_length=200)
    def __unicode__(self):
        return "%s" %(self.name)

class Project(models.Model):
    name = models.CharField(max_length=200)
    employee = models.ForeignKey(Employee)
    def __unicode__(self):
        return "%s, %s" % (self.name, self.employee)

The methods:

from django.http import HttpRequest, HttpResponse,HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import loader,Context
from django.utils import simplejson
from ajax.models import Employee, Project

class ProjectInfo(object):
	"""
	Container for project infos for easy iteration on
	the template.
	"""

    def __init__(self):
        self.project = None
        self.in_charge = ""
        self.employee_list = []

def simpleAjaxTest(request):
	"""Renders some data onto a template"""

    project_list = []
    employee_list  = []
    project_info_list = []
    template = loader.get_template("ajax.html")

    #Fetch data from database
    projects = Project.objects.all()
    employees = Employee.objects.all()

    for employee in employees:
        employee_list.append(employee)

    #For each project in the list create a new ProjectInfo object
    for project in projects:
        pro = ProjectInfo()
        pro.project = project
        pro.in_charge = project.employee
        pro.employee_list = employee_list
        project_info_list.append(pro)

    context = Context({'project_info_list' : project_info_list,})
    return HttpResponse(template.render(context))

def ajaxResponse(request):
	"""Reads some data from request and responses a Json string"""

    project_id = request.GET["project_id"]
    employee = request.GET["employee"]
    response_dict = {"project_id": project_id,"employee": employee}
    return HttpResponse(simplejson.dumps(response_dict), mimetype='application/javascript')

As already stated above, the first method fetches some data from tables and renders it onto the template. The result looks like this:

ajax_tut_table

The second method, the ajaxResponse method, is called on the onchange event of the drop down boxes. From the request it reads the project_id and employee parameters and returns them in a JSON string, which then is handled by the handleSuccess function of the callback. But more to that later.

The javaScript code:

<script type="text/javascript">
function doRequest(x){
	var sUrl;
	var drop_down_box = document.getElementById(x).value;

	// The value of drop_down_box contains the project_id
	// and employee name separated by a comma. Need to split it to built
	// the sURL later.
	var jsonString;
	var data = drop_down_box.split(",")
	var output = document.getElementById("output")
	var switch_column = document.getElementById("switch_" + data[0])

	// Successful server Response.
	var handleSuccess = function(o){
		if(o.responseText !== undefined){
			output.innerHTML =  "<li>Transaction id: " + o.tId + "</li>";
			output.innerHTML += "<li>HTTP status: " + o.status + "</li>";
			output.innerHTML += "<li>Status code message: " + o.statusText + "</li>";
			output.innerHTML += "<li>HTTP headers:<br/>";
			output.innerHTML += o.getAllResponseHeaders + "</li>"
			output.innerHTML += "<li>Server response: " + o.responseText + "</li>";

			// Parse jsonString
			jsonString = o.responseText
			try {
			    var responseData = YAHOO.lang.JSON.parse(jsonString);
			}
			catch (e) {
			    alert("Invalid data returned");
			}

			// Change the employee in the "In Charge column with the one
			// selected from the drop down box.
			switch_column.innerHTML = responseData.employee
		}
	}

	// Response failed.
	var handleFailure = function(o){
		if(o.responseText !== undefined){
			output.innerHTML  = "<li>Transaction id: " + o.tId + "</li>";
			output.innerHTML += "<li>HTTP status: " + o.status + "</li>";
			output.innerHTML += "<li>Status code message: " + o.statusText + "</li>";
		}
	}

	// Callback
	var callback =
	{
	  success:handleSuccess,
	  failure: handleFailure,
	  argument: { foo:"foo", bar:"bar" }
	};

	// Ajax request
	sUrl = 'http://localhost:8000/blog/ajax/submit/?project_id=' + data[0] +'&employee=' + data[1]
	var transaction = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback, null);
};

The complete template code can be viewed here, which also includes the javaScript code.

Basicly when you change the user in the switch column the onchange event of the drop down box calls the doRequest() function and passes the id (which actually consist of of the prefix “drop_” and the project_id) of the drop down box as argument. Then we read it`s value. Since the value actually contains two information, the project_id and employee name, I had to split that string separating it by comma.

var output = document.getElementById(”output”)
var drop_down_box = document.getElementById(x).value;
var data = drop_down_box.split(”,”)
var in_charge_column = document.getElementById(”in_charge_column_” + data[0])

The variable data[0] contains the project_id. The variable output is an HTML element which displays information on successful or failed response. Since we will update the employee in the “in_charge_column” on successful response from server with the name we have selected from the drop down box, we need to fetch it.

The AJAX request part:

// Ajax request
sUrl = ‘http://localhost:8000/blog/ajax/submit/?project_id=’ + data[0] +’&employee=’ + data[1]
var transaction = YAHOO.util.Connect.asyncRequest(’GET’, sUrl, callback, null);

sUrl contains the url string to the corresponding method on the server, the ajaxResponse() method. The mapping of this url to the method is defined in the url.py file.

The url.py:

from django.conf.urls.defaults import *

urlpatterns = patterns('ajax',
    # Example:
    (r'^$', 'views.simpleAjaxTest'),
    (r'^submit/$', 'views.ajaxResponse'),
)

On a successful response from the server the handleSuccess function from callback will be executed. This method displays some information about the response and manipulated the “in_ charge_column”. It will update the column with the employee name which we have selected from the drop down menu.

handleSuccess:

// Successful server Response.
	var handleSuccess = function(o){
		if(o.responseText !== undefined){
			output.innerHTML =  "<li>Transaction id: " + o.tId + "</li>";
			output.innerHTML += "<li>HTTP status: " + o.status + "</li>";
			output.innerHTML += "<li>Status code message: " + o.statusText + "</li>";
			output.innerHTML += "<li>HTTP headers:<br/>";
			output.innerHTML += o.getAllResponseHeaders + "</li>"
			output.innerHTML += "<li>Server response: " + o.responseText + "</li>";

			// Parse jsonString
			jsonString = o.responseText
			try {
			    var responseData = YAHOO.lang.JSON.parse(jsonString);
			}
			catch (e) {
			    alert("Invalid data returned");
			}

			// Change the employee in the "In Charge column with the one
			// selected from the drop down box.
			in_charge_column.innerHTML = responseData.employee
		}
	}

Since I don`t have access to an online Django system where this could be hosted I will post some screenshots:

1.Select a employee from the drop down box.

ajax_tut_table_1

2. See how it updates the “In Charge” column with the selected name.

ajax_tut_table_2

So, using the YUI javaScript framework combined with the Django webframework makes it pretty simple to send AJAX requests.

If you have any questions related to this post, don`t be shy and post it in the comments section. I will try and answer your question asap.