Django AJAX Selects for Admin AutoComplete
django-ajax-selects is a Django app that enhances the Django Admin interface by providing jQuery UI AutoComplete functionality for ForeignKey, ManyToManyField, and CharField lookups. It helps users quickly find and select related objects or text entries in large datasets, improving usability for forms with many options. The current version is 3.0.3, supporting Django 3.2 to 5 and Python 3.10+. Releases are made as needed, typically in response to Django version updates or critical bug fixes.
Common errors
-
ModuleNotFoundError: No module named 'ajax_select'
cause The 'ajax_select' application is not included in Django's `INSTALLED_APPS`.fixAdd `'ajax_select'` to your `INSTALLED_APPS` list in `settings.py`. -
django.urls.exceptions.NoReverseMatch: 'ajax_lookup' is not a registered namespace
cause The URL patterns for `django-ajax-selects` are not included in your project's `urls.py`.fixAdd `path('ajax_select/', include('ajax_select.urls'))` to your project's `urlpatterns` in `urls.py`. -
TypeError: Cannot read properties of undefined (reading 'jQuery') or Cannot read properties of undefined (reading 'django')
cause This often indicates a JavaScript conflict or that jQuery/jQuery UI is not properly loaded, or loaded in a way that conflicts with `django-ajax-selects`. The 'django' object issue was specifically fixed in v3.0.3, but similar problems can arise from other JS conflicts.fixEnsure `django-ajax-selects` is installed and `INSTALLED_APPS` and `urls.py` are configured correctly. If on an older version, upgrade to 3.0.3+. Check if other apps or your base templates are loading conflicting jQuery/jQuery UI versions. For versions 3.0.0+, `django-ajax-selects` bundles its own JS/CSS; remove redundant includes. -
django.core.exceptions.ImproperlyConfigured: 'my_channel_name' is not a valid lookup channel.
cause The lookup channel name specified (e.g., in `make_ajax_form`, `AutoCompleteSelect`, or `AutoCompleteSelectMultiple`) either does not exist or has not been properly registered with `@register('my_channel_name')` or configured in `settings.AJAX_LOOKUP_CHANNELS`.fixVerify that your `LookupChannel` class is decorated with `@register('my_channel_name')` and that 'my_channel_name' exactly matches the string used in your form or admin configuration.
Warnings
- breaking Version 3.0.0 introduced significant changes, dropping support for older Python and Django versions. It now requires Python >= 3.10 and Django >= 3.2. If upgrading from 2.x, ensure your environment meets these new requirements.
- breaking With version 3.0.0, jQuery and jQuery UI assets are now bundled and served directly by `django-ajax-selects`. If you were previously managing these assets yourself or using a custom CDN, you might encounter conflicts or redundant asset loading.
- breaking Version 2.0.0 dropped support for Python < 3.6 and Django < 2.2. Projects on these older versions must upgrade their Django/Python stack first.
- gotcha You must include 'ajax_select' in your Django project's `INSTALLED_APPS` and `path('ajax_select/', include('ajax_select.urls'))` in your root `urls.py`. Failing to do so will lead to `ModuleNotFoundError` or `NoReverseMatch` errors.
- gotcha When using `AutoCompleteSelect` or `AutoCompleteSelectMultiple` in custom forms, ensure the `LookupChannel` argument correctly references a registered lookup channel name (e.g., `AutoCompleteSelect(LookupChannel='my_channel')`). Mismatched names will result in lookups not working.
Install
-
pip install django-ajax-selects
Imports
- LookupChannel
from ajax_select import LookupChannel
- register
from ajax_select import register
- make_ajax_form
from ajax_select import make_ajax_form
- AjaxSelectAdmin
from ajax_select.admin import AjaxSelectAdmin
- AutoCompleteSelect
from ajax_select import AutoCompleteSelect
- AutoCompleteSelectMultiple
from ajax_select import AutoCompleteSelectMultiple
Quickstart
import os
import django
from django.conf import settings
from django.urls import path, include
from django.db import models
from django.contrib import admin
# NOTE: In a real Django project, you would typically integrate these pieces
# into your existing settings.py, urls.py, models.py, lookup_channels.py, and admin.py files.
# The settings.configure() block below is for making this example self-contained and runnable.
# Minimal Django setup for a self-contained example
# In your project, these settings would be in your project's settings.py
settings.configure(
DEBUG=True,
SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'insecure-secret-key-for-development-only'),
ROOT_URLCONF='__main__',
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ajax_select' # <-- Crucial: Add ajax_select to your INSTALLED_APPS
],
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
],
STATIC_URL='/static/',
STATIC_ROOT=os.path.join(os.getcwd(), 'staticfiles'), # Required for collectstatic
# Optional: Configure AJAX_SELECT_BOOTSTRAP = True for Bootstrap theme if using it
)
django.setup()
# 1. Define simple models (in your app's models.py)
class Author(models.Model):
name = models.CharField(max_length=200)
birth_year = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
published_year = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.title
# 2. Create a lookup channel (in your app's lookup_channels.py or similar module)
from ajax_select import LookupChannel, register
@register('authors') # <-- 'authors' is the channel name you'll reference
class AuthorLookup(LookupChannel):
model = Author
search_field = 'name' # Field to search in the model
def get_query(self, q, request):
# Customize your query here
return self.model.objects.filter(name__icontains=q).order_by('name')
def format_item_display(self, obj):
# Customize how results are displayed in the dropdown
return f"{obj.name} ({obj.birth_year or 'N/A'})"
# 3. Register your models with the Admin and apply ajax_select (in your app's admin.py)
from ajax_select.admin import AjaxSelectAdmin
from ajax_select import make_ajax_form
@admin.register(Book)
class BookAdmin(AjaxSelectAdmin):
# Use make_ajax_form to integrate the lookup channel with a ForeignKey
form = make_ajax_form(Book, {'author': 'authors'}) # 'author' is the FK field, 'authors' is the lookup channel name
admin.site.register(Author)
# No need to register Book if using the @admin.register decorator
# 4. Define URL patterns (in your project's urls.py)
urlpatterns = [
path('admin/', admin.site.urls),
path('ajax_select/', include('ajax_select.urls')), # <-- Crucial: Include ajax_select URLs
]
# Example of how you would typically run this in a Django project:
# 1. python manage.py makemigrations myapp
# 2. python manage.py migrate
# 3. python manage.py createsuperuser (to access admin)
# 4. python manage.py runserver
# Then navigate to /admin/ and add a Book to see the autocomplete in action.