As-You-Type Slug Uniqueness Validation

September 26, 2008. Filed under django 72 python 59 jquery 6

Welcome to the fourth and final entry in the Django, jQuery and Ajax tutorial series, which picks up where Layers of Authentication left off.

Because it's the last entry, we're going to do something quick and fun: make the frontpage's slug field validate slugs as you type, by changing the background color of the field to either red (in-use) or blue (available).

Let's get started.

Two Guys, A URL, and A View

First go ahead and open up notes/ and add this url:

(r'^slug_available/$', 'notes.views.slug_available'),

Then open notes/ and add this method:

def slug_available(request):
    if request.method == "GET":
        get = request.GET.copy()
        if get.has_key('slug'):
            slug_str = get['slug']
            if Note.objects.filter(slug=slug_str).count() == 0:
                return HttpResponse(slug_str)
                return HttpResponseServerError(slug_str)
    return HttpResponseServerError("Requires a slug field.")

Often we use the data we return to indicate success or failure of a request, but it's easier, clearer, and (perhaps) truer to http to use response codes to distinguish between success and failure.

For this view, it will return a 200 response code (because we're using HttpResponse) for success, and a 500 reponse code (because of HttpResponseServerError) for failure. We then distinguish between kinds of failure by varying the text returned along with the 500 response code.

Other than that, slug_available is pretty straight-forward, so we'll move on to integrating the view into our templates.

Integrating into notes/note_list.html

We'll start our joyous integration with the list view, so go ahead and open up the notes/note_list.html template.

First, lets fix some of our earlier laziness, and wrap everything in the <script></script> tag in this code:

$(document).ready(function() {

  // All other JavaScript here.

That is a useful jQuery pattern which makes sure your JavaScript loads after the DOM has settled down and is ready to be tampered with. Some really ambiguous and hard to track down issues can arise when you don't use it... so... use it.

Now on to our task at hand: updating the background color of the span input based on slug availability.

It'll look like this (which you'll need to add somewhere within the <script></script> tags in note_list.html):

$("#slug").keyup(function() {
    var slug = this.value;
    var complete = function(res, status) {
       if (status == "success") $("#slug").css('background-color','#A0A0FF');
       else $("#slug").css('background-color','#FFA0A0');
    $.ajax({type:'GET', url:'/slug_available/', data:{'slug': slug }, complete:complete});

If we wanted to, we could compress that a bit by inlining the first line.

$("#slug").keyup(function() {
  var complete = function(res, status) {
    if (status=="success") $("#slug").css('background-color','blue');
    else $("#slug").css('background-color','red');

Then we go inline the complete function as well.

$("#slug").keyup(function() {
  $.get('/slug_available/',{'slug':this.value},complete:function(res, status) {
    if (status=="success") $("#slug").css('background-color','blue');
    else $("#slug").css('background-color','red');

Which seems like a good place to stop.

So with that we have an as-you-type validation system implemented for slugs. This is one Ajax technique that I find to be genuinely useful at conveying additional information to users, and highly recommend integrating into applications where it fits.


You can access the code for this project at its GitHub repository.

(Although, you may have to rename the repository directory to ajax_tut before it runs properly.)

Closing Down The Series

Well, that wraps up the Django, jQuery and Ajax tutorial series. Hopefully it was a bit helpful. I'll end by reiterating a brief warning: Ajax leads to a lot of really terribly user interfaces. Make sure that you're using Ajax because Ajax brings a real benefit, not just because you can.

Let me know where I've made mistakes, and I'll lumber around to correcting them as soon as life permits.