Django search function using JQuery Ajax

In this example, I am going to show how to create a search function in Django using JQuery Ajax. This is a simple way to display results of a search query without reloading the current page or navigating to the another page. We are going to use the Users table which Django generates when doing a ‘python manage.py syncdb’ for the first time.

Step 1: Create an app.

Assuming that we have an existing project, we will start by creating our search app.

‘python manage.py startapp ajaxsearch’ this will create a folder ajaxsearch with files inside.

Step 2: Open the views.py inside the folder ajaxsearch

Edit views.py and insert the following code:

from django.http import Http404, HttpResponse
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.db.models import Q
from django.contrib.auth.models import User
import time

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

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' )

            return render_to_response( 'results.html', { 'results': results, }, 
                                       context_instance = RequestContext( request ) )

The ‘ajax_user_search’ function is called everytime we do a search query (when clicking the submit button).

What it does is search for any matches from the value given by the user against the data in the Users table. ‘q’ is the variable that contains the value given.

Step 3: create a file urls.py inside the ‘ajaxsearch’ folder.

Insert the following code:

from django.conf.urls.defaults import *
from ajaxsearch.views import *

urlpatterns = patterns( '',
         url( r'^
url( r'^users/
                              )

This url pattern ‘url( r’^users/$’, ajax_user_search, name = ‘demo_user_search’ )’ will be used to call the function ‘ajax_user_search’ in our views.py.

Add this line of code to your urls.py in the project root:

( r'^search/', include( 'ajaxsearch.urls' ) ),

my urls.py looks like this:

from django.conf.urls.defaults import patterns, include, url
from django.conf import settings
from django.views.generic.simple import direct_to_template
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url( r'^search/', include( 'ajaxsearch.urls' ) ),
)

urlpatterns += patterns('',
    (r'^media/(?P.*)

Step 4: Create the templates.

Let’s create our html files inside the templates folder. In this example, we will create 3 templates. ‘base.html’, ‘index.html’ and ‘results.html’.

Here is our base.html:

<html>

<head>
<title>Django/jQuery AJAX Search</title>
<link href=”{{ MEDIA_URL }}style.css” rel=”stylesheet” type=”text/css” />          <script type=”text/javascript” src=”http://jqueryjs.googlecode.com/files/jquery-1.2.6.js”></script>

{% block extra_js %}{% endblock %}
    </head>

<body>
<div id=”centered”>

{% block main %}{% endblock %}

</div>
</body>
</html>

Our base.html will provide the skeleton structure defining elements that will be on every page in the site. It has two blocks (‘block extra_js’ and ‘block main’). ‘{% block extra_js %}’ will be filled later with javascript code needed to call a function in our views.py. This function will return a query set according to the keyword given which we are going to create later. Another block,  ‘{% block main %}’ will be used as a region for our search form.

Here is our index.html (this is just a form that asks for the search query):

{% extends ‘base.html’ %}

{% block extra_js %}

<script type=”text/javascript”>
$( document ).ready( function() {
$( ‘#searchSubmit’ ).click( function() {
q = $( ‘#q’ ).val();
$( ‘#results’ ).html( ‘&nbsp;’ ).load( ‘{% url demo_user_search %}?q=’ + q );
});
});

$( document ).ajaxStart( function() {
$( ‘#spinner’ ).show();
}).ajaxStop( function() {
$( ‘#spinner’ ).hide();
});
</script>

{% endblock %}

{% block main %}

<div>
<input id=”q” type=”text”/>
<input id=”searchSubmit” type=”submit” value=”Search”/>
<br/>
<span class=”hint”>Type in a query string to search for users</span>
<div class=”margin”>
<span id=”spinner”><img src=”http://upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif”/></span>
<div id=”results”></div>
</div>
</div>
{% endblock %}

Inside the block ‘extra_js’ are 2 functions. The first javascript function calls the function ‘ajax_user_search’ in the views.py we just created. This javascript function will be called everytime the submit button is clicked. It calls that Python function by accessing the url mapped to it (the url pattern with the name ‘demo_user_search’ in our urls.py inside the folder ajaxsearch). The second javascript function shows and hides the GIF loading image when needed.

Note: When the first function is called, it changes the content of the div with the id ‘results’. The content could be a table of results or a message saying that there are no matches found. So technically, it inserts the code inside the ‘results.html’ which we are going to create later and let Django do it’s job in displaying the necessary information.

Now let’s create our results.html (displays our search results):

{% if results|length %}

<table>
<tr class=’even’>
<td colspan=”3” class=”right”>
<strong>Found {{ results|length }} users</strong>
</td>
</tr>

{% for user in results %}
    <tr class=”{% cycle ‘odd’ ‘even’ %}“>
<td><strong>{{ forloop.counter }}.</strong></td>
<td>
{{ user.first_name }} {{ user.last_name }}<br/>
<span class=”hint”>{{ user.username }}</span>
</td>
<td class=”right”>
<span class=”hint”>
Joined {{ user.date_joined|timesince }} ago<br/>
Last logged in {{ user.last_login|timesince }} ago
</span>
</td>
</tr>
{% endfor %}
    </table>
{% else %}
    <div class=”note”>
Your search yielded no results
</div>
{% endif %}

You can also use this css ‘style.css’:

body {
background-color: #FFF;
font-size: 1.0em;
font-family: “Lucida Grande”, Tahoma, Helvetica, sans-serif;
color: #564b47;
padding: 20px;
margin: 0px;
text-align: center;
}

div { padding: 0; margin: 0; }

table { width: 100%; border: 1px solid #DDDDB2; border-spacing: 0; border-collapse: collapse; }

tr { padding-bottom: 5px; border-bottom: 1px solid #CCC; }

tr.odd { background: #FFF; }

tr.even { background: #FFFFD4; }

td { margin: 0; padding: 5px 5px 5px 3px; vertical-align: top; }

td.right { text-align: right; }

#centered {
text-align: left;
vertical-align: middle;
margin: 0px auto;
padding: 20px;
width: 550px;
background-color: #FFF;
border: 1px solid #CCC;
}

#spinner { display: none; position: relative; }

div.padded { padding-top: 10px; }

div.margin { margin-top: 20px; }

div.clear { clear: both; }

div.note { padding: 15px; background: #FFFFD4; border: 1px solid #DDDDB2; }

.hint { font-size: 0.8em; color: #888; }

That’s it. We are done with our HTML files.

Those are the steps in making a JQuery Ajax search function for Django. We used the Users table to demonstrate how to create it but you can always use other tables you want.

References:

https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects

http://www.nomadjourney.com/2009/01/using-django-templates-with-jquery-ajax/ (no longer available)