Source code for django_choices_js.forms

import json
from typing import Optional

import django.forms

from django_choices_js.models import ChoicesAutocompletePathConfig, autocomplete_path_for_model


[docs] class ChoicesJsMixin: """ The base class of all Choices.js widgets. This adds the media property that includes all necessary css and js tags for Choices.js. """ def __init__(self, choices_opts: dict = None, *args, **kwargs): """ Args: choices_opts (dict): Options that are passed directly to the Choices.js constructor. """ super().__init__(*args, **kwargs) self.choices_opts = choices_opts
[docs] def build_attrs(self, base_attrs, extra_attrs=None): attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs) class_attr = attrs.get('class') attrs['class'] = ' '.join((class_attr.split(' ') if class_attr else []) + ['choices-js-field']) attrs['data-choices-js'] = json.dumps(self.choices_opts) if self.choices_opts else {} return attrs
@property def media(self): return django.forms.Media( css={'screen': ('choices-js/choices.css', 'django-choices.css')}, js=('choices-js/choices.js', 'django-choices.js') )
[docs] class ChoicesJsTextInput(ChoicesJsMixin, django.forms.TextInput): """ A widget for text input that allows multiple entries separated by a delimiter (default ``','``). Example:: text = django.forms.CharField(widget=django_choices_js.ChoicesJsTextInput, choices_opts={'maxItemCount': 3}) """ pass
[docs] class ChoicesJsSelect(ChoicesJsMixin, django.forms.Select): pass
[docs] class ChoicesJsSelectMultiple(ChoicesJsMixin, django.forms.SelectMultiple): pass
[docs] class ChoicesJsModelMixin(ChoicesJsMixin): def __init__(self, choices_opts=None, autocomplete_name=None, *args, **kwargs): if choices_opts is None: choices_opts = {} if 'searchChoices' not in choices_opts: choices_opts['searchChoices'] = False super().__init__(choices_opts, *args, **kwargs) self.autocomplete_name = autocomplete_name
[docs] def build_attrs(self, base_attrs, extra_attrs=None): attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs) if isinstance(self.choices, django.forms.models.ModelChoiceIterator): model = self.choices.queryset.model if not hasattr(model, '__django_choices_js__'): raise InvalidAutocomplete(f'no autocomplete registered for {model.__name__}') path = autocomplete_path_for_model(model, self.autocomplete_name) path_config: Optional[ChoicesAutocompletePathConfig] = model.__django_choices_js__.get(path) if path_config is None: if self.autocomplete_name is None: raise InvalidAutocomplete(f'no default autocomplete registered for {model.__name__}') else: raise InvalidAutocomplete(f'no autocomplete with name {self.autocomplete_name} registered for {model.__name__}') attrs['data-choices-js-autocomplete'] = path_config.path return attrs
[docs] def optgroups(self, name, value, attrs=None): if isinstance(self.choices, django.forms.models.ModelChoiceIterator): if value != ['']: self.choices.queryset = self.choices.queryset.filter(pk__in=value) else: self.choices.queryset = self.choices.queryset.none() return super().optgroups(name, value, attrs)
[docs] class ChoicesJSModelSelect(ChoicesJsModelMixin, django.forms.Select): pass
[docs] class ChoicesJSModelSelectMultiple(ChoicesJsModelMixin, django.forms.SelectMultiple): pass
[docs] class InvalidAutocomplete(Exception): def __init__(self, message): self.message = message