Skip to content
Jan 6 / Nizam Sayeed

Using Django templates with jQuery AJAX

I recently discovered a neat way of displaying data retrieved using jQuery AJAX in concert with Django’s template engine. You can create a view in Django which simply uses the render_to_response shortcut function to render the results server-side and then just use jquery.load to dynamically fetch the results.

Eventhough, returning some raw JSON data is much more efficient as far as bandwidth is concerned, this method is a lot simpler.

I have been using jQuery for over a year now. I have found that its built-in DOM manipulation features are a bit limited, especially for manipulating tables (e.g., adding rows dynamically). This method is much cleaner than doing all that DOM manipulation.

Here is all the jQuery code to handle the search and AJAX spinner display:

$(document).ready(function() {
	$('#searchSubmit').click(function() {
		q = $('#q').val();
		$('#results').html(' ').load('{% url demo_user_search %}?q=' + q);
	});
});

$(document).ajaxStart(function() {
	$('#spinner').show();
}).ajaxStop(function() {
	$('#spinner').hide();
});

Here is the Django view function that does the heavy lifting on the server-side:

def ajax_user_search(request):
    if request.is_ajax():
        q = request.GET.get('q')
        if q is not None:            
            results = User.objects.filter( 
                Q(first_name__contains = q) |
                Q(last_name__contains = q) |
                Q(username__contains = q)).order_by('username')
            
            template = 'results.html'
            data = {
                'results': results,
            }
            return render_to_response(template, data, 
                context_instance = RequestContext(request))

Here are some screenshots of the results:

AJAX operation in progress

AJAX operation in progress

Returned results

Returned results

No results

No results

The sample Django project is included for your perusal and is released under the MIT license. I used the excellent Aptana Studio IDE when working on this demo so it can be imported straight into it as an Aptana project.

Download ajax_user_list.zip

  • Pingback: HamzaED

  • http://www.pagina24.com Claudio

    What if ‘q’ has a space?? You can’t use the ‘load’ function in this case, can you?? Is there an easy way to replace the space for ‘%20′ ??

    • http://www.nomadjourney.com Nizam

      Claudio,

      I believe JavaScript has a built in function called encodeURIComponent( String ) which will encode a specific component of a URI. So the call to jQuery.load() above can be modified to the following to handle spaces and the like:

      .load( ‘{% url demo_user_search %}?q=’ + encodeURIComponent( q ) );

      Here is a link which may be useful:

      http://xkr.us/articles/javascript/encode-compare/

  • Thomas B. Higgins

    Didn’t you mean to say that Django’s built-in DOM manipulation features were a bit limited? In the example you have jQuery handling the display while Django handles the back end, which certainly seems advantageous to me if one is to have flexible DOM manipulation.

    • http://www.nomadjourney.com Nizam

      Thomas,

      I actually did mean to say jQuery. Don’t get me wrong, jQuery is the most awesome JavaScript library out there. Its power is in DOM traversal. It obviously has a very robust DOM manipulation API as well. However, its weakness is in on the fly creation of DOM elements.

      E.g., if I wanted to add rows to a table element for instance, I’d have to set a string variable with the HTML markup for the row and use jQuery.append() to add it to the table. There is no way for me to add the row in a more programmatic kind of way. That’s what I meant. Hope this clears this up.

      – Nizam

    • Aaron

      Take a look at the jQuery datatables plugin — you’ll find it very easy to work with, and it’ll solve your row-creation problem, as well as others (sort, load, interaction) that you didn’t realize you had.

  • NMarcu

    Hello, I need some help. I succed to run your exemple but when I do it on my project I got this error:
    “uncaught exception: Syntax error, unrecognized expression: %}”

    About my code:
    This is from jquery: $( '#test_div' ).html( ' ' ).load( '{% url test_ajax %}');

    I have created the “#test_div” on html page.
    This is the view:
    def test_ajax1( request ):
    if request.is_ajax():
    template = 'operators/operators_list.html'
    data = {
    }
    return render_to_response( template, data, context_instance = RequestContext( request ) )

    This is the url:
    url(r'^operators/', 'ibox2.operators.views.test_ajax1', name='test_ajax'),

    I have the operators_list.html template also created.

    You know why I get this error?

    • http://www.nomadjourney.com Nizam

      Marcu,

      Is the jQuery snippet above inside of a Django template? If not, then the call to the url template tag will not work.

      If it is within a Django template, then check your rendered HTML and see if the call to the url template tag is working properly. You may also want to check for any unclosed template blocks ({% or %}).

    • Sam

      I am facing a similar issue…
      Basically the question is, how do we do a URL lookup at run time using through jquery (ajax)?

      Consider this code…

      $(document).ready( function() {
      $( '#searchSubmit' ).click( function() {
      searchstring = $( '#searchstring' ).val();
      var querystring = { q: searchstring };
      $.getJSON("/customer/srch/",querystring,
      function(data){
      $("#search_results").remove();
      // Add the search_results div to the container
      $("#search_container").append("");
      $.each(data, function(i, customers){
      $( '#search_container' ).html( ' ' ).load( '{% url show_cust customers.fields.id %}' );
      });
      }
      );
      return false;
      });
      });

      Here the

      $( '#search_container' ).html( ' ' ).load( '{% url show_cust customers.fields.id %}' );

      is throwing an error…

      Caught an exception while rendering: Reverse for 'show_cust' with arguments '('',)' and keyword arguments '{}' not found.

      This is so, because the value of customer_id is not known at first. But would only be known once the “searchSubmit” button has been clicked.

      How do I ask the django Templating language to only evaluate the url call at run time & not at first page load?

      I hope I have been clear in explaining the issue.

      Thanks,
      Sameer

    • http://www.nomadjourney.com Nizam

      Sameer,

      There isn’t a way to have Django evaluate that url template tag from the client side. However, there is a way to get around this problem.

      I am assuming that customers.fields.id is set in the template context by your view. If so, you can do something like this in your template’s JavaScript block:

      var customerID = {{ customers.fields.id }};

      And then in the jQuery portion:

      $( '#search_container' ).html( ' ' ).load( '{% url show_cust %}/' + customerID + '/' );

      And that should do the trick.

    • Sameer

      Nizam, thanks for the quick reply.

      No, “customers.fields.id” is not set in the template context.

      I am using Ajax/JSON to pass “customer” objects from the View to the Template (via jQuery).

      Just to make things a bit more clear, finally what I am looking to achieve is to generate entire HTML UI using Ajax (via jQuery). For that I require the “Customer” objects which I am getting thru JSON.

      But the problem is, getting the URL for each customer object (for e.g. /cutomer/21). Ofcourse, I can hard code the URL such as ("/customer/"+ "Customer_ID"), but then it would be a very poor design decision & quite cumbersome to maintain. That’s why I require the reverse URL lookup to work at runtime inside an Ajax (jQuery) call.

    • http://www.nomadjourney.com Nizam

      Let me get this straight. You are getting the customer objects via AJAX/JSON from Django, right? Therefore you can use the extra QuerySet API method to append an extra column for each row containing the URLs (possibly the value returned by the model instance’s get_absolute_url method) for each item before sending it back as a JSON response. Then you could use them as is from your jQuery code without any modification.

  • http://www.grenadepod.com pulegium

    Nizam, just to say thanks for this tutorial that inspired me to write smth similar using django and jquery (which i must admin i never used before!). Only difference is that your code acts upon user instruction (search query) whereas I use jquery to do gradual load of the page (displaying info as it becomes available). Below more details if anyone’s interested:

    http://www.grenadepod.com/2009/11/13/query-data-from-django-site-with-jquery/

    Now I’ve got one question. How would you go about passing information from the HTML back to the site? If you look at my example I use class to identify all objects I want to query and the id holds the object specific information. Again, I’m total muppet when it comes to js/ajax stuff, so just wondering what would the best practises be in approaching this?

    Cheers!

    • http://www.nomadjourney.com Nizam

      @pulegium,

      I just left a comment for your blog post. Thought that it might be the right place to continue the discussion.

  • Peter Rowell

    Nizam -

    I had to do some Django/Ajax interaction on a site I did 2 years ago. We had a separate window called the Video Console and a large list of videos that could be displayed. Each video had a number of components: a URL to the FLV file, descriptive text, URLs to related products, etc. I was concerned about too much knowledge of the page layout being buried either in the back end or in the JS code for the AJAX handling.

    Then I found the jQuery plugin called ‘taconite’! (Cue sounds of angels singing from on high.) See http://malsup.com/jquery/taconite/

    I created a simple utility class to collect the various changes we wanted to make to the browser page. When you call the response() method it gives you a fully compliant XML/Taconite object wrapped in an HttpResponse object and … everything just works!

    Between the taconite jQuery magic on the front, and the simplicity of building/rendering on the back, it’s almost embarrassing how simple taconite makes doing AJAXy stuff.

    I put a quick-and-dirty version of it at:
    http://techbuddy.us/taconite.py.txt

    • http://www.nomadjourney.com Nizam

      Peter,

      Thanks for sharing your experience using jQuery Taconite and Django together. Really good stuff! I’ll have to steal this for my next project. ;)

    • Scott

      @ Peter and @Nizam. Great stuff guys! Thanks!

  • NMarcu

    Hi,

    There is possible to update 2 divs with the same load function?

  • Laurent

    Thank you Nizam. Helpful and neat !

  • Igor Ganapolsky

    I’m really curious what your urls.py looks like. I cannot get your example to work.

    • http://www.nomadjourney.com Nizam

      Here is the urls.py from the sample which can be downloaded here:

      http://www.nomadjourney.com/wp-content/uploads/2009/01/ajax_user_list.zip


      from django.conf.urls.defaults import *
      from django.views.generic.simple import direct_to_template
      from django.contrib.auth.views import login, logout_then_login
      from django.conf import settings


      from django.contrib import admin
      admin.autodiscover()


      urlpatterns = patterns('',
      ( r'^admin/(.*)', admin.site.root ),
      ( r'^site_media/(?P .*)$', 'django.views.static.serve', { 'document_root': settings.MEDIA_ROOT } ),
      ( r'^demo/', include( 'demo.urls' ) ),
      )

    • Cássio

      I cannot get the example work too.

      It seems that the site_media is not found. I put the address hardcoded but have no sucess again.
      That is some configuration that need to be donne?

  • joe

    Is there an easy reason why if I wrap the ‘q’ and ‘searchSubmit’ inputs inside of a form (to allow carriage return submission) that it stops working?

  • http://github.com/comolongo/Yz-Javascript-Django-Template-Compiler Weiss

    This might be a little late, but I recently started a project on github that addresses this problem a little differently. Instead of generating everything with the django templates on the server, I have a script that compiles the django templates into javascript functions. You can then just send JSON data back from the server and plug it into the functions to generate the proper html. The generated functions are in pure javascript so no other plugins are required. Let me know what you think!
    Project: http://github.com/comolongo/Yz-Javascript-Django-Template-Compiler
    Really basic demo: http://yz-demos.appspot.com/yz_djs_demo/

  • Pingback: django jquery ajax 的一个小例子 « Sealyu's Blog

  • Pingback: Ajax, Dajaxice, and Taconite « Why Django?

  • Алибек Датбаев

    trying to comment

  • Zahid

    As soon as i add the extends tag in the template the code stops working while it keeps working otherwise. What could be the reason for that?

  • Ed Sparkes

    Hi, 

    This is really nice, however i have a slight problem. If i try and parse parameters in the second argument to the load it doesnt work. I want to pass my post parameters up and use request.POST.get instead of request.GET.get. 

    Any Ideas??

    Thanks, Ed

    • Anonymous

      Hi Ed,

      Calling jQuery.load like so should POST the data:

      $(‘#results’).html(‘ ’).load(‘{% url demo_user_search %}’, { ‘q’: q });
      By passing the query param ‘q’ as an array (using the optional data parameter), it should automatically POST instead of GET. For more info, check the jQuery.load() docs:http://api.jquery.com/load/