diff --git a/django_select2/__init__.py b/django_select2/__init__.py index d2d415b3..575a0213 100644 --- a/django_select2/__init__.py +++ b/django_select2/__init__.py @@ -9,5 +9,5 @@ """ from django import get_version -if get_version() < '3.2': +if get_version() < "3.2": default_app_config = "django_select2.apps.Select2AppConfig" diff --git a/django_select2/forms.py b/django_select2/forms.py index b40b6207..df3982fe 100644 --- a/django_select2/forms.py +++ b/django_select2/forms.py @@ -54,7 +54,7 @@ import django from django import forms -from django.contrib.admin.widgets import SELECT2_TRANSLATIONS +from django.contrib.admin.widgets import SELECT2_TRANSLATIONS, AutocompleteMixin from django.core import signing from django.db.models import Q from django.forms.models import ModelChoiceIterator @@ -65,7 +65,9 @@ from .conf import settings if django.VERSION < (4, 0): - from django.contrib.admin.utils import lookup_needs_distinct as lookup_spawns_duplicates + from django.contrib.admin.utils import ( + lookup_needs_distinct as lookup_spawns_duplicates, + ) else: from django.contrib.admin.utils import lookup_spawns_duplicates @@ -79,6 +81,9 @@ class Select2Mixin: form media. """ + css_class_name = "django-select2" + theme = None + empty_label = "" def __init__(self, *args, **kwargs): @@ -90,7 +95,7 @@ def build_attrs(self, base_attrs, extra_attrs=None): default_attrs = { "lang": self.i18n_name, "data-minimum-input-length": 0, - "data-theme": settings.SELECT2_THEME, + "data-theme": self.theme or settings.SELECT2_THEME, } if self.is_required: default_attrs["data-allow-clear"] = "false" @@ -102,9 +107,9 @@ def build_attrs(self, base_attrs, extra_attrs=None): attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs) if "class" in attrs: - attrs["class"] += " django-select2" + attrs["class"] += " " + self.css_class_name else: - attrs["class"] = "django-select2" + attrs["class"] = self.css_class_name return attrs def optgroups(self, name, value, attrs=None): @@ -137,6 +142,20 @@ def media(self): ) +class Select2AdminMixin: + """Select2 mixin that uses Django's own select template.""" + + css_class_name = "admin-autocomplete" + theme = "admin-autocomplete" + + @property + def media(self): + return forms.Media( + js=Select2Mixin().media._js, + css=AutocompleteMixin(None, None).media._css, + ) + + class Select2TagMixin: """Mixin to add select2 tag functionality.""" diff --git a/tests/test_forms.py b/tests/test_forms.py index 5a89dfd1..dc991ed2 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -21,6 +21,7 @@ ModelSelect2TagWidget, ModelSelect2Widget, Select2Widget, + Select2AdminMixin, ) from tests.testapp import forms from tests.testapp.forms import ( @@ -175,6 +176,23 @@ def test_theme_setting(self, settings): assert 'data-theme="classic"' in widget.render("name", None) +class TestSelect2AdminMixin: + def test_media(self): + translation.activate("en") + assert tuple(Select2AdminMixin().media._js) == ( + f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", + f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/en.js", + "django_select2/django_select2.js", + ) + + assert dict(Select2AdminMixin().media._css) == { + "screen": [ + "admin/css/vendor/select2/select2.min.css", + "admin/css/autocomplete.css", + ] + } + + class TestSelect2MixinSettings: def test_default_media(self): sut = Select2Widget()