import django_filters from django import forms from django.conf import settings from django.forms import BoundField from django.urls import reverse from utilities.forms import widgets from utilities.views import get_viewname __all__ = ( 'DynamicChoiceField', 'DynamicModelChoiceField', 'DynamicModelMultipleChoiceField', 'DynamicMultipleChoiceField', ) # # Choice fields # class DynamicChoiceField(forms.ChoiceField): def get_bound_field(self, form, field_name): bound_field = BoundField(form, self, field_name) data = bound_field.value() if data is not None: self.choices = [ choice for choice in self.choices if choice[0] == data ] else: self.choices = [] return bound_field class DynamicMultipleChoiceField(forms.MultipleChoiceField): def get_bound_field(self, form, field_name): bound_field = BoundField(form, self, field_name) data = bound_field.value() if data is not None: self.choices = [ choice for choice in self.choices if choice[0] and choice[0] in data ] return bound_field # # Model choice fields # class DynamicModelChoiceMixin: """ Override `get_bound_field()` to avoid pre-populating field choices with a SQL query. The field will be rendered only with choices set via bound data. Choices are populated on-demand via the APISelect widget. Attributes: query_params: A dictionary of additional key/value pairs to attach to the API request initial_params: A dictionary of child field references to use for selecting a parent field's initial value null_option: The string used to represent a null selection (if any) disabled_indicator: The name of the field which, if populated, will disable selection of the choice (DEPRECATED: pass `context={'disabled': '$fieldname'}` instead) context: A mapping of