Hello pals,
In this blog, I am going to guide you to implement autocomplete in Django admin interface. I chose admin interface because it provides CRUD ( CREATE-READ-UPDATE-DELETE ) view for defined models out of the box.
For implementing auto completion feature, I am going to use django-ajax-selects currently maintained by crucialfelix.
Setup
Let's start by creating a django project.
First of all, I'll create a virtual environment .venv. You can create virtual environment just by python -m venv .venv.
Let's activate the virtual environment .venv\Scripts\activate as I am currently on Windows environment.
After that, install django and django-ajax-selects using pip.
pip install django django-ajax-selects
Following installing libraries, let's create django project named autocomplete_demo_project.
django-admin startproject autocomplete_demo_project
Subsequently, Let's create a django app named blog .
python manage.py startapp blog
And register the app 'blog' and 'ajax_select' in INSTALLED_APPS inside settings.py.
# autocomplete_demo_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ajax_select', # new apps
'blog.apps.BlogConfig',
]
Thereafter, let's define URLConfs for ajax_select so it may load the necessary javascripts, stylesheets for autocompletion.
# autocomplete_demo_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from ajax_select import urls as ajax_select_urls
urlpatterns = [
path('ajax_select/', include(ajax_select_urls)),
path('admin/', admin.site.urls),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Models and Lookups
We have to start through defining models which will later be used for observing auto completion in admin panel.
Without adding any complexity, I'll just start with a single field name in Blog model.
# blog/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
class Blog(models.Model):
name = models.CharField(_("Blog"), max_length=50)
def __str__(self):
return self.name
Let's also create a lookup for the field name which fetches the most suitable result by matching the query entered while entering a record in admin panel. For doing so, let's create LookupChannel for our field name (NameLookup) in lookup.py inside blog app directory.
# blog/lookups.py
from ajax_select import register, LookupChannel
from .models import Blog
@register('names')
class NameLookup(LookupChannel):
model = Blog
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q).order_by('name')[:50]
def format_item_display(self, item):
return u"<span class='blog_name'>%s</span>" % item.name
Here, we've observed two methods inside our NameLookup class. Let's dig into both of them:
get_querymethod takesqparameter as query which will be used to filter the record in database. Here, we've used thename__icontainsapproach which will filter the matched records in DB with sub string queryqand return the filtered records.
We may also proceed withname__startswithapproach which only tries to match the starting string with the records in DB with sub string queryqand return the filtered records. But, let's just stick into one approach (name__icontainsapproach) to implement the auto completion.format_item_displaymethods takes each filtered records and displaysblog.name(data) which is the need in our case with proper styling. We can override the display properties to make it look better and match with our preferences.
Also notice that we've registered a lookup name names with register decorator which will later be used with form to match with required form field i.e. The form field with the property names will match with the above lookup.
ModelAdmin and Forms
Ensuing step will be to create Django forms which will be provided as property to our ModelAdmin which we'll later create in admin.py .
# blog/forms.py
from ajax_select.fields import AutoCompleteField
from django import forms
from .models import Blog
class BlogForm(forms.ModelForm):
name = AutoCompleteField('names')
class Meta:
model = Blog
fields = [
'name'
]
It's worth noticing that the field name is an AutoCompleteField with the property names which is a lookup name we've registered in NameLookup class inside blog/lookups.py. It's how we interlink forms and lookups using django-ajax-selects.
Following this, let's create ModelAdmin inside admin.py.
# blog/admin.py
from ajax_select.admin import AjaxSelectAdmin
from django.contrib import admin
from .forms import BlogForm
from .models import Blog
@admin.register(Blog)
class BlogAdmin(AjaxSelectAdmin):
form = BlogForm
What we've done here is overriding the default form property provided by Django Admin and get it replaced by our BlogForm form object.
Also note that, the use of BlogForm isn't limited to ModelAdmin for auto completion. It can also be used in used defined templates by passing form inside context parameter from views.py.
For doing so,
{{ form.media }}
{{ form }}
We need to load ((form.media}} to load the necessary JS and CSS files defined by ajax_selects app.
Observation
After defining lookups, models, forms and modeladmin, now we can make migrations and run the migration files.
python manage.py makemigrations blog
Post hoc, let's run those migration files.
python manage.py migrate
Then, create a superuser for accessing admin interface,
python manage.py createsuperuser
Then, log into 127.0.0.1:8000/admin to access admin interface and navigate to Blog model.
Try adding some records and you'll notice auto completion making work easy for you.
Demo
I've added some records in my models.

Let's try to add another record to observe auto-completion.

Notice that, when I am typing A, the records with the letter A in their name appeared as dropdown so user may autocomplete the record.
Thank you for reading.
Top comments (0)