Django Select2 Integration
django-select2 provides a robust Django integration for the popular Select2 JavaScript library, enhancing dropdowns with search, remote data loading, and custom rendering. The current version is 8.4.8, and it sees frequent minor updates and security patches, typically on a monthly or bi-monthly cadence.
Warnings
- breaking Version 8.3.0 dropped official support for Django versions older than 4.2 LTS and Python versions older than 3.10. Users on older environments must either upgrade or stick to `django-select2` versions `< 8.3.0`.
- security A security vulnerability (CVE-2025-48383 / GHSA-wjrh-hj83-3wh7) was reported where widget instance secret cache keys could leak across multiple requests with a single process.
- gotcha Failure to include `django_select2` in `INSTALLED_APPS` and its URL patterns in `urls.py` will prevent assets from loading and AJAX functionality from working.
- gotcha The JavaScript and CSS assets for Select2 are loaded via Django's `Media` class. For `django-select2` widgets to function correctly, `{{ form.media }}` must be included in your template, ideally in the `<head>` for CSS and before `</body>` for JavaScript.
- gotcha Using `AutoSelect2Widget` or `HeavySelect2Widget` requires setting up a dedicated view (inheriting from `Select2QuerySetView`) to handle the AJAX requests for data. Without this, the autocomplete functionality will not work.
Install
-
pip install django-select2
Imports
- Select2Widget
from django_select2.forms import Select2Widget
- Select2MultipleWidget
from django_select2.forms import Select2MultipleWidget
- AutoSelect2Widget
from django_select2.forms import AutoSelect2Widget
- Select2QuerySetView
from django_select2.views import Select2QuerySetView
- django_select2.urls
from django.urls import include, path; path('select2/', include('django_select2.urls'))
Quickstart
import os
from django import forms
from django.conf import settings
from django.urls import path, include
from django.http import HttpResponse
from django.shortcuts import render
from django_select2.forms import Select2Widget
# Minimal Django settings for testing
settings.configure(
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_select2',
# Add a placeholder app for templates
'my_app'
],
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(__file__), 'templates')],
'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',
],
},
},
],
SECRET_KEY='a_very_secret_key_for_testing_only',
DEBUG=True,
STATIC_URL='/static/',
STATICFILES_FINDERS=[
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
],
ROOT_URLCONF=__name__,
)
# Create a dummy templates directory and file for the quickstart
if not os.path.exists('templates'):
os.makedirs('templates')
with open('templates/quickstart_form.html', 'w') as f:
f.write('''
<!DOCTYPE html>
<html>
<head>
<title>Select2 Quickstart</title>
{{ form.media.css }}
</head>
<body>
<h1>Select2 Form</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
{{ form.media.js }}
</body>
</html>
''')
# forms.py (conceptually)
class MyChoiceForm(forms.Form):
fruit = forms.ChoiceField(
choices=[
('apple', 'Apple'),
('banana', 'Banana'),
('orange', 'Orange'),
('grape', 'Grape'),
('strawberry', 'Strawberry'),
],
widget=Select2Widget(attrs={'data-placeholder': 'Select a fruit'})
)
# views.py (conceptually)
def quickstart_view(request):
if request.method == 'POST':
form = MyChoiceForm(request.POST)
if form.is_valid():
return HttpResponse(f"You selected: {form.cleaned_data['fruit']}")
else:
form = MyChoiceForm()
return render(request, 'quickstart_form.html', {'form': form})
# urls.py (conceptually)
urlpatterns = [
path('select2/', include('django_select2.urls')),
path('', quickstart_view, name='quickstart'),
]
# To run this, you'd typically have a manage.py and runserver,
# but for a self-contained example:
# from django.core.management import call_command
# call_command('runserver', '0.0.0.0:8000')
print("To run this example:")
print("1. Ensure you have django and django-select2 installed.")
print("2. This code snippet directly configures Django for a basic test.")
print("3. In a real project, you'd set up INSTALLED_APPS, URL patterns and templates normally.")
print("4. Access '/' to see the form.")