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 thatdjango.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...