Django Search Autocomplete with Filter

Creating a user-friendly search experience is essential in modern web applications. I’ve noticed that users expect instant feedback as they type, especially when searching through large datasets. Implementing search autocomplete with filtering in Django not only enhances usability but also significantly improves data accessibility.

In this tutorial, I’ll walk you through how to build a search autocomplete feature with filtering in Django. I will share my firsthand experience, guiding you through the setup, coding, and deployment of this feature.

Methods to Search Autocomplete with Filter

When building applications like job boards, real estate listings, or local business directories in the USA, users want to quickly find relevant results without typing full queries. Autocomplete helps by suggesting possible matches as users type, while filters narrow down results based on specific criteria, like location or category.

Combining both makes the search experience intuitive and efficient. From my experience, users stay longer and engage more when the search is fast and relevant.

Check out Build a Chat App in Django

Method 1: Basic Search Autocomplete with Filter in Django

Let’s start with a simple but powerful approach using Django views and the JavaScript fetch API.

Step 1: Set up Django Project and App

Create a Django project and app if you haven’t already.

django-admin startproject USASearchProject
cd USASearchProject
python manage.py startapp searchapp

Add searchapp to your INSTALLED_APPS in settings.py.

Step 2: Define Your Model

For this example, I’ll create a model for US cities with their state and population.

# searchapp/models.py
from django.db import models

class City(models.Model):
    name = models.CharField(max_length=100)
    state = models.CharField(max_length=2)  # State abbreviation, e.g., CA, NY
    population = models.IntegerField()

    def __str__(self):
        return f"{self.name}, {self.state}"

Run migrations:

python manage.py makemigrations
python manage.py migrate

Step 3: Populate Sample Data

You can use Django admin or a data migration to add sample cities. For the sake of brevity, here is a simple script you can run in the Django shell:

python manage.py shell
from searchapp.models import City

cities = [
    {"name": "Los Angeles", "state": "CA", "population": 3970000},
    {"name": "San Francisco", "state": "CA", "population": 884000},
    {"name": "New York", "state": "NY", "population": 8419000},
    {"name": "Buffalo", "state": "NY", "population": 255000},
    {"name": "Chicago", "state": "IL", "population": 2716000},
]

for city in cities:
    City.objects.create(**city)
exit()

Step 4: Create the Autocomplete API View

We will create an API endpoint that accepts a search term and an optional filter (state), returning matching cities.

# searchapp/views.py
from django.http import JsonResponse
from django.views import View
from .models import City

class CityAutocomplete(View):
    def get(self, request):
        query = request.GET.get('q', '')
        state_filter = request.GET.get('state', '')

        cities = City.objects.all()

        if query:
            cities = cities.filter(name__icontains=query)
        if state_filter:
            cities = cities.filter(state__iexact=state_filter)

        results = [{"id": city.id, "name": str(city)} for city in cities[:10]]  # Limit to 10 results

        return JsonResponse(results, safe=False)

Read How to Deploy an AI Model with Django

Step 5: Configure URLs

Add the API endpoint URL.

# searchapp/urls.py
from django.urls import path
from .views import CityAutocomplete

urlpatterns = [
    path('autocomplete/cities/', CityAutocomplete.as_view(), name='city-autocomplete'),
]

Include this in your main urls.py:

# USASearchProject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('searchapp/', include('searchapp.urls')),
]

Step 6: Create the Frontend Template

Create a simple template to demonstrate the autocomplete with a filter.

<!-- searchapp/templates/searchapp/search.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>City Search Autocomplete with Filter</title>
    <style>
        #autocomplete-list {
            border: 1px solid #ddd;
            max-height: 150px;
            overflow-y: auto;
            position: absolute;
            background: white;
            width: 300px;
        }
        #autocomplete-list div {
            padding: 10px;
            cursor: pointer;
        }
        #autocomplete-list div:hover {
            background-color: #e9e9e9;
        }
    </style>
</head>
<body>
    <h2>Search US Cities</h2>
    <label for="stateFilter">Filter by State:</label>
    <select id="stateFilter">
        <option value="">All States</option>
        <option value="CA">California (CA)</option>
        <option value="NY">New York (NY)</option>
        <option value="IL">Illinois (IL)</option>
    </select>

    <br /><br />

    <input type="text" id="searchInput" placeholder="Type city name..." autocomplete="off" style="width:300px; padding:8px;" />
    <div id="autocomplete-list"></div>

    <script>
        const searchInput = document.getElementById('searchInput');
        const stateFilter = document.getElementById('stateFilter');
        const autocompleteList = document.getElementById('autocomplete-list');

        function clearAutocomplete() {
            autocompleteList.innerHTML = '';
        }

        function createAutocompleteItem(city) {
            const div = document.createElement('div');
            div.textContent = city.name;
            div.addEventListener('click', () => {
                searchInput.value = city.name;
                clearAutocomplete();
            });
            return div;
        }

        async function fetchAutocomplete() {
            const query = searchInput.value.trim();
            const state = stateFilter.value;

            if (query.length === 0) {
                clearAutocomplete();
                return;
            }

            const url = new URL('/searchapp/autocomplete/cities/', window.location.origin);
            url.searchParams.append('q', query);
            if (state) {
                url.searchParams.append('state', state);
            }

            try {
                const response = await fetch(url);
                if (!response.ok) throw new Error('Network response was not ok');
                const cities = await response.json();

                clearAutocomplete();

                if (cities.length === 0) {
                    const noResult = document.createElement('div');
                    noResult.textContent = 'No results found';
                    autocompleteList.appendChild(noResult);
                    return;
                }

                cities.forEach(city => {
                    autocompleteList.appendChild(createAutocompleteItem(city));
                });
            } catch (error) {
                console.error('Fetch error:', error);
            }
        }

        searchInput.addEventListener('input', fetchAutocomplete);
        stateFilter.addEventListener('change', () => {
            if (searchInput.value.trim()) {
                fetchAutocomplete();
            }
        });

        // Close autocomplete list if clicked outside
        document.addEventListener('click', (e) => {
            if (e.target !== searchInput) {
                clearAutocomplete();
            }
        });
    </script>
</body>
</html>

Step 7: Add the Template View

Add a simple view to render this template.

# searchapp/views.py (add this import and view)
from django.shortcuts import render

def city_search_view(request):
    return render(request, 'searchapp/search.html')

Update URLs:

# searchapp/urls.py (add this path)
from .views import city_search_view

urlpatterns = [
    path('', city_search_view, name='city-search'),
    path('autocomplete/cities/', CityAutocomplete.as_view(), name='city-autocomplete'),
]

I executed the above example code and added the screenshot below.

django form autocomplete

Check out File Upload in Django

Method 2: Use Django Autocomplete Light (Advanced)

If you want to avoid writing JavaScript from scratch, I recommend using the Django Autocomplete Light package. It integrates seamlessly with Django forms and provides powerful autocomplete widgets with filtering support.

From my experience, this method is ideal for projects with complex forms and multiple autocomplete fields.

Read JWT Authentication Using Django Rest Framework

Conclusion

Implementing a search autocomplete with a filter in Django might seem daunting at first, but breaking it down into manageable parts makes it straightforward. The first method I shared is lightweight and customizable, perfect for most projects targeting users in the USA who expect fast and relevant search results.

If you want to scale or add more features like multi-select filters, consider using third-party packages like Django Autocomplete Light.

Feel free to adapt the example to your datasets and enhance the UI for better usability.

You may read other Django-related tutorials:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.