7 min read

Django JavaScript Integration: AJAX and jQuery

Django JavaScript Integration: AJAX and jQuery

Develop AJAX applications using Django and jQuery

  • Learn how Django + jQuery = AJAX
  • Integrate your AJAX application with Django on the server side and jQuery on the client side
  • Learn how to handle AJAX requests with jQuery
  • Compare the pros and cons of client-side search with JavaScript and initializing a search on the server side via AJAX
  • Handle login and authentication via Django-based AJAX

This will allow us to create a results page as shown:

When someone clicks OK, the data is saved on the server, and also shown on the page.

Let’s get started on how this works.

Including a plugin

We include a jQuery plugin on a page by including jQuery, then including the plugin (or plugins, if we have more than one). In our base.html, we update:

{% block footer_javascript_site %}
<script language=”JavaScript” type=”text/javascript”
src=”/static/js/jquery.js”></script>
<script language=”JavaScript” type=”text/javascript”
src=”/static/js/jquery-ui.js”></script>
<script language=”JavaScript” type=”text/javascript”
src=”/static/js/jquery.jeditable.js”></script>
{% endblock footer_javascript_site %}


This is followed by the footer_javascript_section and footer_javascript_page blocks. This means that if we don’t want the plugin ,which is the last inclusion, to be downloaded for each page, we could put it in overridden section and page blocks. This would render as including the plugin after jQuery.

How to make pages more responsive

We would also note that the setup, with three JavaScript downloads, is appropriate for development purposes but not for deployment. In terms of YSlow client-side performance optimization, the recommended best practice is to have one HTML/XHTML hit, one CSS hit at the top, and one JavaScript hit at the bottom. One of the basic principles of client-side optimization, discussed by Steve Souders (see http://developer.yahoo.com/yslow/) is,since HTTP requests slow the page down, the recommended best practice is to have one (preferably minifed) CSS inclusion at the top of the page, and then one (preferably minifed) JavaScript inclusion at the bottom of each page. Each HTTP request beyond this makes things slower, so combining CSS and/or JavaScript requests into a single concatenated file is low-hanging fruit to improve how quick and responsive your web pages appear to users.

For deployment, we should minify and combine the JavaScript. As we are developing, we also have JavaScript included in templates and rendered into the delivered XHTML; this may be appropriate for development purposes. For deployment though, as much shared functionality as possible should be factored out into an included JavaScript fle. For content that can be delivered statically, such as CSS, JavaScript, and even non-dynamic images, setting far-future Expires/Cache-Control headers is desirable. (One practice is to never change the content of a published URL for the kind of content that has a far-future expiration set, and then if it needs updating, instead of changing the content at the same location, leave the content where it is, publish at a new location possibly including a version number, and reference the new location.)

A template handling the client-side requirements

Here’s the template. Its view will render it with an entity and other information. At present it extends the base directly; it is desirable in many cases to have the templates that are rendered extend section templates, which in turn extend the base. In our simple application, we have two templates which are directly rendered to web pages. One is the page that handles both search and search results—and the other, the page that handles a profile, from the following template:

{% extends “base.html” %}


We include honorifics before the name, and post-nominals after. At this point we do not do anything to make it editable.

{% extends “base.html” %}
Following earlier discussion, we include honorifcs before the name, and
post-nominals after. At this point we do not do anything to make it editable.
{% block head_title %}
{{ entity.honorifics }} {{ entity.name }} {{ entity.post_nominals }}
{% endblock head_title %}
{% block body_main %}


There is one important point about Django and the title block. The Django developers do not fnd it acceptable to write a templating engine that produces errors in production if someone attempts to access an undefned value (by typos, for instance). As a result of this design decision, if you attempt to access an undefned value, the templating engine will silently insert an empty string and move on. This means that it is safe to include a value that may or may not exist, although there are ways to test if a value exists and is nonempty, and display another default value in that case. We will see how to do this soon. Let’s move on to the main block, defned by the last line of code.

Once we are in the main block, we have an h1 which is almost identical to the title block, but this time it is marked up to support editing in place. Let us look at the honorifics span; the name and post_nominals spans work the same way:

<h1>
<span id=”Entity_honorifics_{{ entity.id }}” class=”edit”>
{% if entity.honorifics %}
{{ entity.honorifics }}
{% else %}
Click to edit.
{% endif %}
</span>


The class edit is used to give all $(“.edit”) items some basic special treatment with Jeditable; there is nothing magical about the class name, which could have been replaced by user-may-change-this or something else. edit merely happens to be a good name choice, like almost any good variable/function/object name.

We create a naming convention in the span’s HTML ID which will enable the server side to know which—of a long and possibly open-ended number of things we could intend to change—is the one we want. In a nutshell, the convention is modelname_feldname_instanceID. The frst token is the model name, and is everything up to the first underscore. (Even if we were only interested in one model now, it is more future proof to design so that we can accommodate changes that introduce more models.)

The last token is the instance ID, an integer. The middle token, which may contain underscores (for example post_nominals in the following code), is the feld name. There is no specifc requirement to follow a naming convention, but it allows us to specify an HTML ID that the server-side view can parse for information about which feld on which instance of which model is being edited.

We also provide a default value, in this case Click to edit, intended not only to serve as a placeholder, but to give users a sense on how this information can be updated.

We might also observe that here and in the following code, we do not presently have checks against race conditions in place. So nothing here or in the following code will stop users from overwriting each others’ changes. This may be taken as a challenge to refne and extend the solution to either prevent race conditions or mitigate their damage.

<span id=”Entity_name_{{ entity.id }}” class=”edit”>
{% if entity.name %}
{{ entity.name }}
{% else %}
Click to edit.
{% endif %}
</span>
<span id=”Entity_post_nominals_{{ entity.id }}” class=”edit”>
{% if entity.post_nominals %}
{{ entity.post_nominals }}
{% else %}
Click to edit.
{% endif %}
</span>
</h1>


This approach is an excellent frst approach but in practice is an h1 with three slots that say Click to edit on a profle, creating needless confusion. We move to a simplifed:

<span id=”Entity_name_{{ entity.id }}” class=”edit”>
{% if entity.name %}
{{ entity.name }}jQuery In-place Editing Using Ajax

{% else %}
Click to edit.
{% endif %}
</span>
<span id=”Entity_post_nominals_{{ entity.id }}” class=”edit”>
{% if entity.post_nominals %}
{{ entity.post_nominals }}
{% else %}
Click to edit.
{% endif %}
</span>
</h1>


Taken together, the three statements form the heading in this screenshot:

If we click on the name (for instance) it becomes:

The image is presently a placeholder; this should be expanded to allow an image to be uploaded if the user clicks on the picture (implementing consistent-feeling behavior whether or not we do so via the same plugin). We also need the view and urlpattern on the backend:

<h1 class=”edit” id=”Entity_name_{{ entity.id }}”>
{{ entity.name }}
</h1>


LEAVE A REPLY

Please enter your comment!
Please enter your name here