Lo-Fi Python

Feb 05, 2024

Adding City Name Autocomplete to a Django Form With jQuery + AJAX

Below is a slightly modified adaptation of the Espere.in Step By Step Guide by Abdulla Fajal. I needed to make a few changes to the code to get things to work. I also expanded the example to show how I imported cities data to the Django model. In this post, I'll show how you can use AJAX and jQuery Autocomplete with a Django model to create a form with city auto-completion.

Add a Model to models.py

1
2
3
class City(models.Model):
    city_name = models.CharField("Origen", max_length=200)
    country = models.CharField("PaĆ­s", max_length=200)

Register the City Model in admin.py

1
2
3
4
from django.contrib import admin
from .models import City

admin.site.register(City)

Migrate the Django Model

python manage.py makemigrations City
python manage.py migrate

Add Auto-complete TextInput() to forms.py

The key items here are the "id" attribute holding the value "search-input" and the "name" attribute with value "city_name". Together, these values will tell jQuery for which form element to render the autocomplete view and which model field you targeting to fill into the autocomplete view.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from django import forms
from bookings.models import Booking

class BookingForm(forms.ModelForm):
    class Meta:
        model = Booking
        fields = "__all__"
        widgets = {
            "city": forms.TextInput(
                attrs={
                    "class": "form-control",
                    "id": "search-input",
                    "name": "city_name",
                    "placeholder": "Type to search",
                }
            )
        }

Download the World Cities Database from Simplemaps

The World Cities Database basic version is free and allowed for commercial use. In this example, this provides the cities data.

Import the Cities Database to Django Model

Now we need to import the cities to our Django model. I achieved this by running the below code in the Django shell and entering each line individually. The code was modified from a Stack Overflow post. The World Cities data stores the city in the first column (index 0) and the country in the 5th column (index 4).

python manage.py shell
1
2
3
4
5
6
7
8
import csv
from django.apps import apps

City = apps.get_model(app_label="bookings", model_name="City")
with open("worldcities.csv") as f:
    reader = csv.reader(f)
    for row in reader:
        _, created = City.objects.get_or_create(city=row[0], country=row[4],)
running Python in the Django shell

View Your City Model in the Admin Panel

Enter the below command to start your local Django development server. Then you can go to http://127.0.0.1:8000/admin in a web browser to see your model on the back-end.

python manage.py runserver

Add jQuery Scripts to HTML File

Add the jquery import scripts to your HTML <head> tag.

1
2
3
4
5
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" type="text/css" media="all" />

<!-- Add jQuery and jQuery UI JavaScript -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

Add the jQuery autocomplete script to the bottom of your HTML. This is where we reference the "search-input" id in our form and specify the url route "/ajax_calls/search/".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<script>
$(document).ready(function(){
    $("#search-input").autocomplete({
        source: "/ajax_calls/search/",
        minLength: 2,
        open: function(){
            setTimeout(function () {
                $('.ui-autocomplete').css('z-index', 99);
            }, 0);
        }
    });
});
</script>

Add the Autocomplete View to Views.py

Note this script is using the XMLHttpRequest API, which is used in combination with AJAX.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import json
from django.apps import apps
from django.forms.models import model_to_dict
from django.shortcuts import render
from forms import BookingForm
from django.http import HttpResponse, HttpResponseRedirect


def index(request):
    """Displays an HTML page with a form. If the request is a post, save the data to the DB."""
    if request.method == "POST":
          # Create a form instance and populate it with data from the request.
          form = BookingForm(request.POST)
          if form.is_valid():
              new_booking = form.save()
              return HttpResponseRedirect(f"/confirmation_page")
    context = {}
    context["form"] = BookingForm()
    return render(request, "simple_django_form.html", context)


def autocomplete(request):
    """Show the City model records via AJAX + jQuery."""
    if request.headers.get("x-requested-with") == "XMLHttpRequest":
        City = apps.get_model(app_label="bookings", model_name="City")
        term = request.GET["term"]
        search_results = City.objects.filter(city_name__startswith=term)
        cities = [f"{result.city_name}, {result.country}" for result in search_results]
        data = json.dumps(cities)
   else:
        data = "fail"
   return HttpResponse(data, "application/json")


def confirmation_page(request):
    """Show a confirmation page thanking the client for their business."""
    return HttpResponse("Thanks for signing up!")

Write the HTML for a Simple Django Form

Here is the template I used. It differs slightly from the template in the Django docs.

1
2
3
4
5
6
7
8
{% extends 'base.html' %}
{% block content %}
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit">
</form>
{% endblock %}

Understanding Ajax + XMLHttpRequest

Ajax is a technique that uses XMLHttpRequest to exchange data with a web server without reloading the whole page. XMLHttpRequest is an object that allows web apps to make HTTP requests and receive the responses programmatically using JavaScript. Ajax stands for Asynchronous JavaScript and XML, which means that the data exchange can happen in the background, while the user interacts with the web page. - Bing AI

Add the URL Route to urls.py

1
2
3
4
5
6
7
8
9
from django.urls import path
from . import views

app_name = "your_app_name"
urlpatterns = [
    path("", views.index, name="index"),
    path("confirmation_page/", views.confirmation_page, name="confirmation page"),
    path('ajax_calls/search/', views.autocomplete, name='city_autocomplete'),
]

Voila! The City Autocomplete View

adding autocomplete to a Django form with jQuery

Note: to achieve the appearance of the form text box and autocomplete dropdown, I installed the django-bootstrap-v5 python module

This felt very rewarding to see once it was working. I stretched my abilities outside of coding only in Python to achieve this functionality in my website. Someday I would like to be an experienced Javascript developer also. jQuery has been a staple in web development for many years. Auto-complete is just one of the features that this core Javascript library enables. I am definitely intrigued to explore jQuery further.

Want to read more about Django? Check out my notes on Django here.