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_query
method takesq
parameter as query which will be used to filter the record in database. Here, we've used thename__icontains
approach which will filter the matched records in DB with sub string queryq
and return the filtered records.
We may also proceed withname__startswith
approach which only tries to match the starting string with the records in DB with sub string queryq
and return the filtered records. But, let's just stick into one approach (name__icontains
approach) to implement the auto completion.format_item_display
methods 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)