Adjax documentation contents

Getting started

Welcome to Adjax

Design

There are three components to Adjax:

  • Functions for preparing an Ajax response
  • Template tags for preparing Ajax-optimised HTML
  • A Javascript library for handling responses from our system

Other Ajax Frameworks

Many other people are of course doing similar things with Django and Ajax. Adjax does basic Ajax tasks well and cleanly, but other libraries offer features that may be more useful for you:

  • File upload progress
  • Dynamic choices and predictive combo boxes

What’s next?

You might like to read the Quick install guide or start reading through the tutorial.

Quick install guide

The easiest way to install Adjax is to use use pip, if you have it:

pip install adjax

If you don’t, and you prefer the old school easy_install, then the following command is for you:

easy_install adjax

Not So Quick install

If you don’t have easy_install or pip installed, you will need to do things manually. Firstly, install Django by following the installation instructions at http://docs.djangoproject.com/en/dev/intro/install/.

Next download the Adjax release from http://code.google.com/p/django-adjax/. To unpack and install it, run the following from your shell:

tar xvzf adjax-1.1.tar.gz
cd adjax-1.1.0/
python setup.py install

That’s it, you’ve installed everything you need to install. You can now try the tutorial.

Development version

For those you like to help out, you can check out the development version here:

git clone git@github.com:willhardy/Adjax.git

Adjax Framework Tutorial

This tutorial will help you add some basic Ajax functionality to your site, introducing you to the Adjax framework. It assumes you have already installed the Adjax framework. The tutorial also assumes you know Django well enough to create your own app using views, url config and templates.

Writing an Ajax view

An ajax view is just like any other view in Django, a simple function that takes a request and returns a response. Instead of rendering a template and returning an HttpRequest() object directly (or through render_to_response), you register data and request for javascript changes and let the Adjax framework prepare a suitable JSON response for you.

Create the following view in your app:

import adjax

def hello_world(request):
    adjax.replace(request, 'h1', 'Hello world')
    return adjax.response(request)

To make this do what we want it to do, we need to do two things. Firstly, plug the Django view into your site as you normally would (install the app, add an entry to your url configuration). Secondly, we need to add the appropriate Javascript to call the view and process the response. You will need to prepare another view, which will prepare the HTML required to run our Ajax query. For the purposes of this tutorial, here is a simple view that will do that:

from django.shortcuts import render_to_response
from django.template.context import RequestContext

def index(request):
    return render_to_response('index.html', context_instance=RequestContext(request))

And a simple urls.py which will connect our two views:

from django.conf.urls.defaults import *

urlpatterns = patterns('myapp.views',
    url(r'^$', 'index', name="index"),
    url(r'^hello_world/$', 'hello_world', name="hello_world"),
)

To add the appropriate Javascript, we need to edit the index.html template, adding the following HTML:

<html>
<body>
    <h1>Replace Me Please</h1>
    <a href="{% url hello_world %}">Update</a>

    <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.min.js"></script>
    <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.adjax.js"></script>
    <script>
        $('a').adjaxify();
    </script>
</body>
</html>

This template contains four important elements:

  • our h1 tag, which will be replaced
  • a link to start the Ajax query when the user feels like it
  • javascript library imports: one for JQuery, one for Adjax
  • hand written javascript to turn our link into an Ajax requesting link (adjaxify)

Fire up the django development server and point your browser at http://localhost:8000/. You will be shown a very simple page with our old heading and a link. If you click the link the text will be replaced, without refreshing the entire page.

Users without Javascript

If you can, turn off Javascript and reload the page. If your server is in DEBUG mode, clicking on the link will provide information on the Ajax response, as well as the url where non-javascript users will be redirected to. If a user does not have javascript enabled, the Ajax view will still be called (performing any relevant actions) and the user will be redirected to where they came from. The page refresh is slower than a partial, Ajax-based refresh, but it should show the equivalent information. This is known as graceful degredation and is ‘built-in’ to Adjax.

More examples please

More examples can be found in the test suite, which contains a working demonstration and tests of all of Adjax features. Play with the demonstation (http://localhost:8000/demo), have a read through the views and templates to see how it can be used.

What else is possible?

This is just a simple demonstration of how everything fits together. The Adjax framework has a number of other features, which you can read about in the Adjax view functions reference, the Adjax template tag reference and the Adjax javascript reference. Here you will read how Adjax implements useful functionality, such as:

  • replacing HTML elements (what we just did)
  • hiding HTML elements
  • displaying messages to the user
  • updating displayed information from a Django model instance
  • submitting and validating forms
  • redirecting the browser
  • providing custom information in the JSON response
  • including django templates
  • customising the javascript implementation (eg the way messages are shown or hidden).

See also

If you’re new to Django and Python, you may want to read up about them. A useful starting guide is in the Django documentation.

API Reference

Adjax in your views

Introduction

The Adjax framework handles the communication between your view and the browser. To implement Ajax features manually, you would need to collect relevant information for the browser, pass it in a JSON response and deal with the data using javascript. Since a number of tasks are very common, the Adjax framework provides a standard packaging with a convenient API. Now, your views don’t have to deal with the details of packaging a JSON response.

The following common tasks are handled by the API:

  • User messages
  • Browser redirection (javascript based)
  • Form validation
  • Data update (data from a django model)
  • Hiding/replacing HTML elements
  • Re-Rendering of sections of a page (template inclusion)

Overview

To use Adjax in your views, you only need to call one of the functions that prepare content (see below) and return adjax.response(request). For example:

import adjax

def my_view(request):
    # Adds a "replace" directive to the prepared content
    adjax.replace(request, 'h1', 'My new title')

    # Returns the prepared content as JSON data
    return adjax.response(request)

That’s it. The resulting JSON encoded data will look something like this:

{
"replace": {
    "h1": "My new title"
}
}

The Adjax javascript library will understand this data and replace the relevant element as you asked it to. In your view, you can add as many directives as you like, and they will all be returned together once your view function returns adjax.response(request).

Warning

To avoid some browsers’ caching of Ajax responses, a unique GET parameter is added to every Adjax request. If your code relies on request.GET being empty or containing only your own data, you will need to change it.

User messages

Adjax makes use of Django’s message framework, to avoid reinventing the wheel and to allow you to reuse any code on your site that makes use of Django’s messages. You can either add the messages using Django’s API or using Adjax, both approaches have the same effect:

If you want the messages to be pushed to the browser on the Ajax response, you need to explicity say so by passing the include_messages to the response. Otherwise, the messages will be held until next time (perhaps in a normal django-message-using view).

http://docs.djangoproject.com/en/dev/ref/contrib/messages/

adjax.debug(request, message)
adjax.info(request, message)
adjax.success(request, message)
adjax.warning(request, message)
adjax.error(request, message)

These functions are simply convenient shortcuts to the relevant function in django.contrib.messages. The following view pushes five messages of various levels to the browser.

import adjax

def my_view(request):
    adjax.debug(request, '%s SQL statements were executed.' % count)
    adjax.info(request, 'Three credits remain in your account.')
    adjax.success(request, 'Profile details updated.')
    adjax.warning(request, 'Your account expires in three days.')
    adjax.error(request, 'Document deleted.')

    return adjax.response(request, include_messages=True)

You can also use Django’s message API, especially if you want to access some more sophisticated features of the message framework.

import adjax
from django.contrib import messages
SERIOUSLY_CRAZY_ERROR = 99

def my_view(request):
    messages.info(request, 'The messages framework can be used directly too.')
    messages.add_message(request, SERIOUSLY_CRAZY_ERROR, 'Explosion imminent.')

    return adjax.response(request, include_messages=True)

Browser redirection

Often, an Ajax request may trigger the need for a redirect. The Adjax framework allows the developer to trigger a browser-based redirect from the view.

adjax.redirect(request, to, *args, **kwargs)

Ask the browser to redirect to the given URL. The given target can be a relative or absolute path, a Django model (with get_absolute_url), or a named URL name. In the last case, the arguments and keyword arguments are used to resolve the URL. This operates exactly in the same way that django.core.urlresolvers.redirect() does.

import adjax

def my_view(request):
    if 1+1 == 2:
        return adjax.redirect(request, 'my_success_url')

    adjax.info(request, "Let's stay here for a while.")

    return adjax.response(request, include_messages=True)

The view need not end on the redirect. In the following example, the view continues after the redirect command and messages are shown after the redirect (if the target view chooses to show them).

import adjax

def my_view(request):
    if 1+1 == 2:
        adjax.redirect(request, 'my_success_url')
        adjax.success(request, 'Congratulations!')

    return adjax.response(request)

Form validation

Form validation can be performed on an Ajax request.

adjax.form(request, form)

Validates the given form and provids error messages to browser.

import adjax

def my_view(request):
    form = MyForm(request.POST)

    adjax.form(request, form)
    return adjax.response(request)

Data update

Often an Ajax request will alter attribute values on a Django model. Adjax provides a way to update all the existing values on the page.

adjax.update(request, model_instance, attributes)

Updates previous uses of data from the given model_instance. The attributes argument is a list of attributes that are updated. These must be explicitly provided, so that only the necessary data is sent (in plaintext) to the browser.

import adjax

def my_view(request):
    my_obj = MyModel.objects.get(pk=1)

    adjax.update(request, my_obj, ('name', 'color'))
    return adjax.response(request)

Hiding/replacing HTML elements

adjax.hide(request, name=element_name)

Ask the browser to hide the given element. You will need to use the named_element template tag to mark the element with the same element_name

adjax.replace(request, name=element_name, value=value)

Ask the browser to replace the given element with the given value. You will need to use the named_element template tag to mark the element with the same element_name

import adjax

def my_view(request):
    adjax.hide(request, name='sidebar')
    adjax.replace(request, name='title', value='Hello World')
    return adjax.response(request)

The keyword arguments are necessary, as the previous behaviour needs to be supported. Previously it was only possible to provide the element_name as a CSS selector, for example #my-element-id, .my-class. If you do this, pass the element_name directly (without keyword arguments), but it is strongly advised to use the approach above, and this direct approach my be deprecated in the future.

adjax.hide(request, element_name)

Ask the browser to hide the given element. The given element_name as a CSS selector, for example #my-element-id, .my-class.

adjax.replace(request, element_name, value)

Ask the browser to replace the given element with the given value. The given element_name as a CSS selector, for example #my-element-id, .my-class.

import adjax

def my_view(request):
    adjax.hide(request, 'sidebar')
    adjax.replace(request, 'title', 'Hello World')
    return adjax.response(request)

Re-Rendering of sections of a page

adjax.render(request, template_name, context=None, context_instance=None)

Re-render all instances of the included template, using the given context.

import adjax

def my_view(request):
    adjax.render(request, 'my_app/template.html', {'title': 'Hello World'})
    return adjax.response(request)

Adjax in your templates

For some of the more useful features in the Adjax framework, such as data value updates and section reloading (template inclusion), you’ll need to make use of some template tags.

Data value updates

Data elements can be marked for updating the {% adjax %} tag. Simply use the tag on a django object as you would when presenting the data using a {{ myobj }} variable tag. Filters are not yet supported.

{% load ajax %}

<p>My name is {% adjax my_obj.name %}.</p>

The resulting HTML looks something like this:

<p>My name is <span class="d-d2z8sbbs2b7p212yfno8mi81djjnbqf">Tree</span>.</p>

To just get the value of the key used (for use in eg custom javascript processing of the returned data), use the {% adjax_key %} template tag:

{% load ajax %}

<p>The key is "{% adjax_key my_obj.name %}".</p>

The resulting HTML looks something like this:

<p>The key is "d-d2z8sbbs2b7p212yfno8mi81djjnbqf".</p>

Section Reloading (template inclusion)

You can include a template which you intend to reload using Adjax by using the {% adjax_include %} template tag. The tag simply takes an argument being the name of the relevant template.

{% load ajax %}

{% adjax_include "myapp/template.html" %}

The following HTML is then generated:

<div class="tpl-b4hf2396929rw5tjfaqni5077m41d2b">
  Here is the content of the included template.
</div>

There are also two optional arguments to the {% adjax_include %} tag. The first is prefix, for adding a prefix to the class name (eg tpl-left-abc123xyz). This is useful where the same template is included twice or more on a given page, and you don’t want to update all of them together.

The second optional argument allows you to customise the wrapper HTML element. By default it is a <div> element.

Here are the two optional arguments in action:

{% load ajax %}

{% adjax_include "myapp/template.html" prefix="left" wrapper="span" %}

The following HTML is then generated:

<span class="tpl-left-b4hf2396929rw5tjfaqni5077m41d2b">
  Here is the content of the included template.
</span>

To just get the value of the key used (for use in eg custom javascript processing of the returned data), use the {% adjax_include_key %} template tag:

{% load ajax %}

<p>The key is: "{% adjax_include_key "myapp/template.html" prefix="left" %}"</p>

The following HTML is then generated:

<p>The key is: "tpl-left-b4hf2396929rw5tjfaqni5077m41d2b"</p>

Named elements

Adjax allows you to give HTML elements a name, which can be referred to in your views. The name you choose is then encoded and can be used in the templates. This approach is encouraged, as opposed to refering to the html classes, IDs or elements directly in your python code. There are a number of benefits:

  • HTML/CSS isn’t constrained by the python code
  • HTML/CSS can be changed without changing or retesting the python code
  • The python code can be written without knowing the HTML structure or the names of classes
  • Names chosen to represent elements can be more meaningful to the python developer than existing classes

Eventually this may become the only way to hide/replace HTML elements using the Adjax API.

{% load ajax %}

<span class="{% named_element "my special element" %}">Hello World</span>

The following HTML is then generated:

<span class="n-puplfq3ch3bd9peq6212nk3tht5631y">Hello World</span>

And you can refer to your element in your view:

def my_view(request):
    adjax.hide(name="my special element")
    return adjax.response(request)

The Adjax Javascript API

In order to use Adjax, you will need to load javascript that will initiate the Ajax request and process the response. In general, this is as simple as linking to the Adjax library, and enabling it for a given link or form.

Javascript libraries

The Adjax library can be found at media/js/jquery.adjax.js in the adjax module. A compatible version of the required jquery library is also available.

To include them, simply copy the files into your MEDIA_ROOT (or use a symbolic link) add add the appropriate html. For example:

<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.adjax.js"></script>

Basic Use

To enable a link or form, simply call the .adjaxify() method on the relevant element. For example:

<a id="my-link" href="{% url my_ajax_view %}">Do some Ajaxing</a>

<script type="text/javascript">
    $('#my-link').adjaxify();
</script>

Advanced customisation

The .adjaxify() method can also take a single argument, being a callback function, which is called after the Ajax request is complete and the data has been processed. A single argument is passed to the callback, containing the json data returned by the view.

<script type="text/javascript">
    $('#my-link').adjaxify(function(data) { if (!data.forms) {alert("Success!");} });
</script>

The way messages are displayed can also be customised. This is done by defining your own callbacks in jQuery.adjax_callbacks.

For example, the following overrides the default implementation of the show_message function, with a customised version that slides down with custom HTML, and slides up a few seconds later if it is not an error message:

$.adjax_callbacks.show_message = function(message) {
    msg_content = jQuery('<div class="bar1"><p>'+message.content+'</p><a href="#" class="close">Close</a></div>');
    msg_content.hide();
    jQuery('#messages').prepend(msg_content);
    msg_content.slideDown('slow');
    if (message.level < 40) { msg_content.wait(2000).slideUp('slow') }
    $('.bar1 .close').click(function() {$(this).closest('.bar1').remove();});
}

Topical guides

Ajax in Django - Best Practices

The following information is not specific to the Adjax framework, but rather use of Ajax in general. It is intended to provide helpful information for tackling scenarios that the Adjax library itself is not built do directly cater for. Put simply, it is a place for ideas, approaches and features that do not belong in a framework.

Essential knowledge

Some problems are universal and need to be considered by developers.

Browser Caching

Internet Explorer is known to cache Ajax GET requests, which can cause some issues if your responses change. There are a few approaches to this:

  • Use a POST request
  • Append a unique GET parameter
  • Use request headers (does not appear to work reliably)

jQuery has a cache parameter for their $.ajax() function, which makes use of the second approach above. Adjax consequently takes the same approach.

Graceful degredation

To be completed...

Performance Optimisation

To be completed...

Indices, glossary and tables