Custom lookups allow you to define custom filters that can be used in database queries. By default, Django provides a set of built-in lookups such as exact, icontains, gt, lt, etc., which allow you to perform common filtering operations on query sets. However, sometimes you may need to perform more complex or specialized filtering that isn’t covered by the built-in lookups. In this article, we will see how to write custom lookups in Django.
How to Write Custom Lookups in Django?Below, are the Implementation of how to write custom lookups in Django in Python:
Starting the Project FolderTo start the project use this command
django-admin startproject custom_lookup_project cd custom_lookup_project To start the app use this command
python manage.py startapp custom_lookup_app Now add this app to the ‘settings.py’
INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "custom_lookup_app", ] File Structure
 File Structure Setting Necessary Filescustom_lookup_app/models.py : Below code defines a Django model called Person with a single field name of type CharField with a maximum length of 100 characters.
Python3
# custom_lookup_app/models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
custom_lookup_app/views.py: Django view function searches for Person objects based on a case-insensitive exact match to a query string provided in the request GET parameters. If a match is found, it renders the ‘index.html’ template with the matching persons ; otherwise, it renders an empty queryset
Python3
# custom_lookup_app/views.py
from django.shortcuts import render
from .models import Person
def search_person(request):
if 'query' in request.GET:
query = request.GET['query']
persons = Person.objects.filter(name__iexact=query)
else:
persons = Person.objects.none()
return render(request, 'index.html', {'persons': persons})
custom_lookup_project/lookups.py : Below,code defines a custom lookup CaseInsensitiveExact for Django models, enabling case-insensitive exact matching in queries. It overrides the as_sql method to generate SQL that converts both sides of the comparison to lowercase, facilitating a case-insensitive comparison. This lookup can be used for fields where case sensitivity is not desired, such as names or titles.
Python3
# custom_lookup_app/lookups.py
from django.db.models import Lookup
from django.db.models.functions import Lower
class CaseInsensitiveExact(Lookup):
lookup_name = 'iexact'
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return f"LOWER({lhs}) = LOWER({rhs})", params
custom_lookup_project/__init__.py : Below code enhances Django’s CharField to incorporate a custom lookup named CaseInsensitiveExact , which facilitates case-insensitive exact matching in database queries within the custom_lookup_app .
Python3
# custom_lookup_app/__init__.py
from django.db.models import CharField
from .lookups import CaseInsensitiveExact
CharField.register_lookup(CaseInsensitiveExact)
custom_lookup_project/urls.py : This is the URL which is connect views with templates.
Python3
from django.contrib import admin
from django.urls import path
from custom_lookup_app.views import search_person
urlpatterns = [
path('admin/', admin.site.urls),
path('', search_person, name='search_person'),
]
Creating GUItemplates/index.html : This HTML template displays search results for persons. It includes a search form where users can input a name to search. If there are matching persons, their names are listed; otherwise, it shows a message indicating no results were found.
HTML
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search Results</title>
</head>
<body>
<h1>Search Results</h1>
<form method="GET">
<input type="text" name="query" placeholder="Search by name" value="{{ request.GET.query }}">
<button type="submit">Search</button>
</form>
{% if persons %}
<ul>
{% for person in persons %}
<li>{{ person.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No results found.</p>
{% endif %}
</body>
</html>
admin.py: Here we are registering our models.
Python3
from django.contrib import admin
from .models import *
from django.db.models import Sum
admin.site.register(Person)
Deployment of the ProjectRun these commands to apply the migrations:
python3 manage.py makemigrations python3 manage.py migrate Run the server with the help of following command:
python3 manage.py runserver Output:

Video Demonstration
|