Monday, January 2, 2012

Using jQuery Auto Complete in Django

I recently implemented jquery auto complete in django. I thought it might be helpful to write down the entire process. At least, it can serve as a note for me in the future.

Assuming you have a project module. One of the field champion is the foreign key to the auth user. And you want the champion field to have the auto complete feature as the editor types a name in the text box.

models.py:
  1. from django.db import models
  2. class Project(models.Model):
  3.      title = models.CharField(max_length=200)
  4.      champion = models.ForeignKey(User)


In the forms.py below, as you noticed, an extra field champion_display is added, and champion is turned to a hidden field. This is because we want the auto complete text box to show the name of the selected user not the id. The id will be assigned to the hidden field champion.  

forms.py:
  1. from django import forms

  2. class ProjectForm(forms.ModelForm):
  3.      champion_display = forms.CharField(max_length=100, help_text='type name or username or email')
  4.      class_Meta:
  5.           model = Project
  6.           fields=('title', 'champion_display', 'champion',)

  7.      def __init__(self, *args, **kwargs):
  8.           super(ProjectForm, self).__init__(*args, **kwargs)
  9.           self.field['champion_display'].label = "Add a Champion"
  10.           self.fields['champion'].widget = forms.HiddenInput()

In your project urls.py, add the champion auto complete url.
         
urls.py:       
  1. from django.conf.urls.defaults import patterns, url

  2. urlpatterns = patterns('projects.views',
  3.      url(r'^add/$', 'add'),
  4.      url(r'^champion_auto_complete/$', 'champion_auto_complete', name='champion_auto_complete'),
  5. )

views.py:
  1. from django.http import HttpResponse
  2. from django.contrib.auth.models import User
  3. from django.utils import simplejson

  4. def champion_auto_complete(request):
  5.      q = request.REQUEST('term']
  6.      users = User.objects.filter(is_active=True)
  7.      users_list = []

  8.      for u in users:
  9.           value = '%s, %s (%s) - %s' % (u.last_name, u.first_name, u.username, u.email)
  10.           u_dict = {'id': u.id, 'label': value, 'value': value}
  11.           users_list.append[u_dict]

  12.      return HttpResponse(simplejson.dumps(users_list),mimetype='application/json')


In the Project template, you need to include: jqueryui css, jquery and jqueryui.

templates/projects/add.html:
  1. ......
    <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />

  2. ......
  3. <form action="" method="post">{% csrf_token %}
  4. <div class="forms">
  5.     {{ form }}
  6.     <input type="submit" name="submit" value="Save" />
  7. </div>
  8. </form>
  9. ......

  10. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
  11. <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>

  12.  <script type="text/javascript">
  13.    $(document).ready(function(){  
  14.     $( "#id_champion_display" ).autocomplete({
  15.       source: "{% url champion_auto_complete %}",
  16.       selectFirst:true,
  17.       minLength:2,
  18.       select:function(event,ui) {
  19.         $("#id_champion").val(ui.item.id)
  20.       }
  21.         });
  22.        
  23.    });