jQuery UI Autocomplete with Python/Django

I have been developing a website using Python/Django and the HTML 5 / Javascript / JQuery documentation is lacking.  I wanted to make a text widget that uses Ajax to query the database for suggestions, i.e. autocomplete.  After a lot of searching, here is what I figured out.  In short: JQuery UI.

I am using a class based Django form in my views.py to create the form with the autocomplete text entry on the index page of the site.  (I am going to have to do some C-style indentation to get this Python code to wrap on my page).

class IndexForm(forms.Form):
    category = forms.CharField(max_length=100,
          widget=forms.TextInput
             (attrs={'placeholder':'Category', 'autofocus':'true'}))

Here is the section from index.html that renders the form (again, I am wrapping lines to fit onto the blog page).

<section>
    <form action="/" method="post">
        {% csrf_token %}    <!-- <><><> FIXME -->
        {{ form.as_p }}
        <input type="submit" value="Category"/>
        {% if invalidCategory %}
            <p class ="YPBodyText">There is no match to 
                                       '{{ invalidCategory }}'.</p>    
        {% endif %}
    </form>
</section>

One thing to note is that I am using {% csrf_token %} directly on the webpage.  This is a no-no for front facing pages.  I have a work around for form submission and ajax and will post about that soon.  Please note that you must include jQuery and jQuery UI on your page for the autocomplete to work.  And now we’ll look at index.js for the jQuery UI call.  In our class based form in our views.py, we created a text widget called ‘category’.  It can be found in the DOM as ‘id_category’.

$(document).ready(function() {
    $("#id_category").autocomplete({ source:'SuggestCategory' });
});

As you can see, the autocomplete will make an ajax call to $URL/SuggestCategory.  Here is the line in our urls.py that routes the call to the right view in our views.py.

url(r'^SuggestCategory/$', views.SuggestCategory.as_view()),

And finally back to views.py for the class-based view that responds to the Ajax call.  Since the Ajax call has no side effects on the database, it is handled using the GET method.  I wrote an internal method that searches the ‘text’ column of the ‘category’ table in my objects.py.  If the start of any of these fields matches the submission in ‘starts_with’, we add it to a list, and returned it in JSON format.

class SuggestCategory(generic.View):

    def _get_category_list(self, max_results=0, starts_with=''):
        #import pdb; pdb.set_trace()
        categories = []
        cat_list = []
        if starts_with:
            categories = Categories.objects.filter
                           (category_text__istartswith=starts_with)

        max_len = len(categories)
        if max_results > 0 and max_len > max_results:
            max_len = max_results

        for cat in categories[:max_len]:
            cat_list.append(cat.category_text)

        return cat_list

    def get(self, request):
        #import pdb; pdb.set_trace()
        cat_list = self._get_category_list
                   (DEF_AUTO_COMPLETE_RESULTS, request.GET['term'])
        return HttpResponse(json.dumps(cat_list), 
                                 content_type = "application/json")

Enjoy!

Comments are closed.