API Documentation


Settings for Django-Select2.

class django_select2.conf.Select2Conf(**kwargs)[source]

Bases: appconf.base.AppConf

Settings for Django-Select2.

LIB_VERSION = '4.0.12'

Version of the Select2 library.

CACHE_BACKEND = 'default'

Django-Select2 uses Django’s cache to sure a consistent state across multiple machines.

Example of settings.py:

    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
    'select2': {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",

# Set the cache backend to select2


To ensure a consistent state across all you machines you need to user a consistent external cache backend like Memcached, Redis or a database.


Should you have copied the example configuration please make sure you have Redis setup. It’s recommended to run a separate Redis server in a production environment.


The timeout of select2’s caching backend determines how long a browser session can last. Once widget is dropped from the cache the json response view will return a 404.

CACHE_PREFIX = 'select2_'

If you caching backend does not support multiple databases you can isolate select2 using the cache prefix setting. It has set select2_ as a default value, which you can change if needed.

JS = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/js/select2.min.js'

The URI for the Select2 JS file. By default this points to the Cloudflare CDN.

If you want to select the version of the JS library used, or want to serve it from the local ‘static’ resources, add a line to your settings.py like so:

SELECT2_JS = 'assets/js/select2.min.js'

If you provide your own JS and would not like Django-Select2 to load any, change this setting to a blank string like so:



Change this setting to a local asset in your development environment to develop without an Internet connection.

CSS = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/css/select2.min.css'

The URI for the Select2 CSS file. By default this points to the Cloudflare CDN.

If you want to select the version of the library used, or want to serve it from the local ‘static’ resources, add a line to your settings.py like so:

SELECT2_CSS = 'assets/css/select2.css'

If you provide your own CSS and would not like Django-Select2 to load any, change this setting to a blank string like so:



Change this setting to a local asset in your development environment to develop without an Internet connection.

I18N_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/js/i18n'

The base URI for the Select2 i18n files. By default this points to the Cloudflare CDN.

If you want to select the version of the I18N library used, or want to serve it from the local ‘static’ resources, add a line to your settings.py like so:

SELECT2_I18N_PATH = 'assets/js/i18n'


Change this setting to a local asset in your development environment to develop without an Internet connection.

I18N_AVAILABLE_LANGUAGES = ['ar', 'az', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en', 'es', 'et', 'eu', 'fa', 'fi', 'fr', 'gl', 'he', 'hi', 'hr', 'hu', 'id', 'is', 'it', 'ja', 'km', 'ko', 'lt', 'lv', 'mk', 'ms', 'nb', 'nl', 'pl', 'pt-BR', 'pt', 'ro', 'ru', 'sk', 'sr-Cyrl', 'sr', 'sv', 'th', 'tr', 'uk', 'vi', 'zh-CN', 'zh-TW']

List of available translations.

List of ISO 639-1 language codes that are supported by Select2. If currently set language code (e.g. using the HTTP Accept-Language header) is in this list, Django-Select2 will use the language code to create load the proper translation.

The full path for the language file consists of:

from django.utils import translations

full_path = "{i18n_path}/{language_code}.js".format(

settings.DJANGO_SELECT2_I18N refers to I18N_PATH.

class Meta[source]

Bases: object

Prefix for all Django-Select2 settings.

prefix = 'SELECT2'


Django-Select2 Widgets.

These components are responsible for rendering the necessary HTML data markups. Since this whole package is to render choices using Select2 JavaScript library, hence these components are meant to be used with choice fields.

Widgets are generally of two types:

1. Light – They are not meant to be used when there are too many options, say, in thousands. This is because all those options would have to be pre-rendered onto the page and JavaScript would be used to search through them. Said that, they are also one the most easiest to use. They are a drop-in-replacement for Django’s default select widgets.

2(a). Heavy – They are suited for scenarios when the number of options are large and need complex queries (from maybe different sources) to get the options.

This dynamic fetching of options undoubtedly requires Ajax communication with the server. Django-Select2 includes a helper JS file which is included automatically, so you need not worry about writing any Ajax related JS code. Although on the server side you do need to create a view specifically to respond to the queries.

2(b). Model – Model-widgets are a further specialized versions of Heavies. These do not require views to serve Ajax requests. When they are instantiated, they register themselves with one central view which handles Ajax requests for them.

Heavy and Model widgets have respectively the word ‘Heavy’ and ‘Model’ in their name. Light widgets are normally named, i.e. there is no ‘Light’ word in their names.

Inheritance diagram of django_select2.forms
class django_select2.forms.Select2Mixin[source]

Bases: object

The base mixin of all Select2 widgets.

This mixin is responsible for rendering the necessary data attributes for select2 as well as adding the static form media.

empty_label = ''
build_attrs(base_attrs, extra_attrs=None)[source]

Add select2 data attributes.

optgroups(name, value, attrs=None)[source]

Add empty option for clearable selects.


Construct Media as a dynamic property.

class django_select2.forms.Select2TagMixin[source]

Bases: object

Mixin to add select2 tag functionality.

build_attrs(base_attrs, extra_attrs=None)[source]

Add select2’s tag attributes.

class django_select2.forms.Select2Widget(attrs=None, choices=())[source]

Bases: django_select2.forms.Select2Mixin, django.forms.widgets.Select

Select2 drop in widget.

Example usage:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ('my_field', )
        widgets = {
            'my_field': Select2Widget


class MyForm(forms.Form):
    my_choice = forms.ChoiceField(widget=Select2Widget)
class django_select2.forms.Select2MultipleWidget(attrs=None, choices=())[source]

Bases: django_select2.forms.Select2Mixin, django.forms.widgets.SelectMultiple

Select2 drop in widget for multiple select.

Works just like Select2Widget but for multi select.

class django_select2.forms.Select2TagWidget(attrs=None, choices=())[source]

Bases: django_select2.forms.Select2TagMixin, django_select2.forms.Select2Mixin, django.forms.widgets.SelectMultiple

Select2 drop in widget for for tagging.

Example for django.contrib.postgres.fields.ArrayField:

class MyWidget(Select2TagWidget):

    def value_from_datadict(self, data, files, name):
        values = super().value_from_datadict(data, files, name):
        return ",".join(values)

    def optgroups(self, name, value, attrs=None):
        values = value[0].split(',') if value[0] else []
        selected = set(values)
        subgroup = [self.create_option(name, v, v, selected, i) for i, v in enumerate(values)]
        return [(None, subgroup, 0)]
class django_select2.forms.HeavySelect2Mixin(attrs=None, choices=(), **kwargs)[source]

Bases: object

Mixin that adds select2’s AJAX options and registers itself on Django’s cache.

dependent_fields = {}

Return URL from instance or by reversing data_view.

build_attrs(base_attrs, extra_attrs=None)[source]

Set select2’s AJAX attributes.

render(*args, **kwargs)[source]

Render widget and register it in Django’s cache.


Add widget object to Django’s cache.

You may need to overwrite this method, to pickle all information that is required to serve your JSON response view.

class django_select2.forms.HeavySelect2Widget(attrs=None, choices=(), **kwargs)[source]

Bases: django_select2.forms.HeavySelect2Mixin, django_select2.forms.Select2Widget

Select2 widget with AJAX support that registers itself to Django’s Cache.

Usage example:

class MyWidget(HeavySelect2Widget):
    data_view = 'my_view_name'


class MyForm(forms.Form):
    my_field = forms.ChoiceField(
class django_select2.forms.HeavySelect2MultipleWidget(attrs=None, choices=(), **kwargs)[source]

Bases: django_select2.forms.HeavySelect2Mixin, django_select2.forms.Select2MultipleWidget

Select2 multi select widget similar to HeavySelect2Widget.

class django_select2.forms.HeavySelect2TagWidget(attrs=None, choices=(), **kwargs)[source]

Bases: django_select2.forms.HeavySelect2Mixin, django_select2.forms.Select2TagWidget

Select2 tag widget.

class django_select2.forms.ModelSelect2Mixin(*args, **kwargs)[source]

Bases: object

Widget mixin that provides attributes and methods for AutoResponseView.

model = None
queryset = None
search_fields = []

Model lookups that are used to filter the QuerySet.


search_fields = [
max_results = 25

Maximal results returned by AutoResponseView.


Add widget’s attributes to Django’s cache.

Split the QuerySet, to not pickle the result set.

filter_queryset(request, term, queryset=None, **dependent_fields)[source]

Return QuerySet filtered by search_fields matching the passed term.

  • request (django.http.request.HttpRequest) – The request is being passed from the JSON view and can be used to dynamically alter the response queryset.
  • term (str) – Search term
  • queryset (django.db.models.query.QuerySet) – QuerySet to select choices from.
  • **dependent_fields – Dependent fields and their values. If you want to inherit from ModelSelect2Mixin and later call to this method, be sure to pop everything from keyword arguments that is not a dependent field.

Filtered QuerySet

Return type:



Return QuerySet based on queryset or model.

Returns:QuerySet of available choices.
Return type:QuerySet

Return list of lookup names.

optgroups(name, value, attrs=None)[source]

Return only selected options and set QuerySet from ModelChoicesIterator.


Return option label representation from instance.

Can be overridden to change the representation of each choice.

Example usage:

class MyWidget(ModelSelect2Widget):
    def label_from_instance(obj):
        return str(obj.title).upper()
Parameters:obj (django.db.models.Model) – Instance of Django Model.
Returns:Option label.
Return type:str
class django_select2.forms.ModelSelect2Widget(*args, **kwargs)[source]

Bases: django_select2.forms.ModelSelect2Mixin, django_select2.forms.HeavySelect2Widget

Select2 drop in model select widget.

Example usage:

class MyWidget(ModelSelect2Widget):
    search_fields = [

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ('my_field', )
        widgets = {
            'my_field': MyWidget,


class MyForm(forms.Form):
    my_choice = forms.ChoiceField(


The ModelSelect2(Multiple)Widget will try to get the QuerySet from the fields choices. Therefore you don’t need to define a QuerySet, if you just drop in the widget for a ForeignKey field.

class django_select2.forms.ModelSelect2MultipleWidget(*args, **kwargs)[source]

Bases: django_select2.forms.ModelSelect2Mixin, django_select2.forms.HeavySelect2MultipleWidget

Select2 drop in model multiple select widget.

Works just like ModelSelect2Widget but for multi select.

class django_select2.forms.ModelSelect2TagWidget(*args, **kwargs)[source]

Bases: django_select2.forms.ModelSelect2Mixin, django_select2.forms.HeavySelect2TagWidget

Select2 model widget with tag support.

This it not a simple drop in widget. It requires to implement you own value_from_datadict() that adds missing tags to you QuerySet.


class MyModelSelect2TagWidget(ModelSelect2TagWidget):
    queryset = MyModel.objects.all()

    def value_from_datadict(self, data, files, name):
        '''Create objects for given non-pimary-key values. Return list of all primary keys.'''
        values = set(super().value_from_datadict(data, files, name))
        # This may only work for MyModel, if MyModel has title field.
        # You need to implement this method yourself, to ensure proper object creation.
        pks = self.queryset.filter(**{'pk__in': list(values)}).values_list('pk', flat=True)
        pks = set(map(str, pks))
        cleaned_values = list(values)
        for val in values - pks:
        return cleaned_values


Django-Select2 URL configuration.

Add django_select to your urlconf if you use any ‘Model’ fields:

from django.urls import path

path('select2/', include('django_select2.urls')),
django_select2.urls.path(route, view, kwargs=None, name=None, *, Pattern=<class 'django.urls.resolvers.RoutePattern'>)


JSONResponse views for model widgets.

class django_select2.views.AutoResponseView(**kwargs)[source]

Bases: django.views.generic.list.BaseListView

View that handles requests from heavy model widgets.

The view only supports HTTP’s GET method.

get(request, *args, **kwargs)[source]

Return a django.http.JsonResponse.


    'results': [
            'text': "foo",
            'id': 123
    'more': true

Get QuerySet from cached widget.


Paginate response by size of widget’s max_results parameter.


Get and return widget from cache.

Raises:Http404 – If if the widget can not be found or no id is provided.
Returns:Widget from cache.
Return type:ModelSelect2Mixin


Shared memory across multiple machines to the heavy AJAX lookups.

Select2 uses django.core.cache to share fields across multiple threads and even machines.

Select2 uses the cache backend defined in the setting SELECT2_CACHE_BACKEND [default=``default``].

It is advised to always setup a separate cache server for Select2.


DjangoSelect2 handles the initialization of select2 fields automatically. Just include {{ form.media.js }} in your template before the closing body tag. That’s it!

If you insert forms after page load or if you want to handle the initialization yourself, DjangoSelect2 provides a jQuery plugin, replacing and enhancing the Select2 plugin. It will handle both normal and heavy fields. Simply call djangoSelect2(options) on your select fields.:


You can pass see Select2 options if needed:

$('.django-select2').djangoSelect2({placeholder: 'Select an option'});

Please replace all your .select2 invocations with the here provided .djangoSelect2.

Security & Authentication

Security is important. Therefore make sure to read and understand what the security measures in place and their limitations.

Set up a separate cache. If you have a public form that uses a model widget make sure to setup a separate cache database for Select2. An attacker could constantly reload your site and fill up the select2 cache. Having a separate cache allows you to limit the effect to select2 only.

You might want to add a secure select2 JSON endpoint for data you don’t want to be accessible to the general public. Doing so is easy:

class UserSelect2View(LoginRequiredMixin, AutoResponseView):

class UserSelect2WidgetMixin(object):
    def __init__(self, *args, **kwargs):
        kwargs['data_view'] = 'user-select2-view'
        super(UserSelect2WidgetMixin, self).__init__(*args, **kwargs)

class MySecretWidget(UserSelect2WidgetMixin, ModelSelect2Widget):
    model = MySecretModel
    search_fields = ['title__icontains']