class ModelMultipleChoiceField
from django.forms import ModelMultipleChoiceField
A MultipleChoiceField whose choices are a model QuerySet.
Ancestors (MRO)
- ModelMultipleChoiceField
- ModelChoiceField
- ChoiceField
- Field
Attributes
Defined in | |
---|---|
default_error_messages = {'list': 'Enter a list of values.', 'invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.', 'invalid_pk_value': '“%(pk)s” is not a valid value.'}
|
ModelMultipleChoiceField |
default_error_messages = {'invalid_choice': 'Select a valid choice. That choice is not one of the available choices.'}
|
ModelChoiceField |
default_error_messages = {'invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.'}
|
ChoiceField |
default_error_messages = {'required': 'This field is required.'}
|
Field |
default_validators = []
|
Field |
empty_values = [None, '', [], (), {}]
|
Field |
Properties
def
choices():
¶
ModelChoiceField
Getter
def _get_choices(self):
# If self._choices is set, then somebody must have manually set
# the property self.choices. In this case, just return self._choices.
if hasattr(self, '_choices'):
return self._choices
# Otherwise, execute the QuerySet in self.queryset to determine the
# choices dynamically. Return a fresh ModelChoiceIterator that has not been
# consumed. Note that we're instantiating a new ModelChoiceIterator *each*
# time _get_choices() is called (and, thus, each time self.choices is
# accessed) so that we can ensure the QuerySet has not been consumed. This
# construct might look complicated but it allows for lazy evaluation of
# the queryset.
return self.iterator(self)
Setter
def _set_choices(self, value):
# Setting choices also sets the choices on the widget.
# choices can be any iterable, but we call list() on it because
# it will be consumed more than once.
if callable(value):
value = CallableChoiceIterator(value)
else:
value = list(value)
self._choices = self.widget.choices = value
def
choices():
¶
ChoiceField
Getter
def _get_choices(self):
return self._choices
Setter
def _set_choices(self, value):
# Setting choices also sets the choices on the widget.
# choices can be any iterable, but we call list() on it because
# it will be consumed more than once.
if callable(value):
value = CallableChoiceIterator(value)
else:
value = list(value)
self._choices = self.widget.choices = value
def
queryset():
¶
ModelChoiceField
Getter
def _get_queryset(self):
return self._queryset
Setter
def _set_queryset(self, queryset):
self._queryset = None if queryset is None else queryset.all()
self.widget.choices = self.choices
Methods
def
_check_values(self, value):
¶
ModelMultipleChoiceField
Given a list of possible PK values, return a QuerySet of the corresponding objects. Raise a ValidationError if a given value is invalid (not a valid PK, not in the queryset, etc.)
def _check_values(self, value):
"""
Given a list of possible PK values, return a QuerySet of the
corresponding objects. Raise a ValidationError if a given value is
invalid (not a valid PK, not in the queryset, etc.)
"""
key = self.to_field_name or 'pk'
# deduplicate given values to avoid creating many querysets or
# requiring the database backend deduplicate efficiently.
try:
value = frozenset(value)
except TypeError:
# list of lists isn't hashable, for example
raise ValidationError(
self.error_messages['list'],
code='list',
)
for pk in value:
try:
self.queryset.filter(**{key: pk})
except (ValueError, TypeError):
raise ValidationError(
self.error_messages['invalid_pk_value'],
code='invalid_pk_value',
params={'pk': pk},
)
qs = self.queryset.filter(**{'%s__in' % key: value})
pks = {str(getattr(o, key)) for o in qs}
for val in value:
if str(val) not in pks:
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
params={'value': val},
)
return qs
def
bound_data(self, data, initial):
¶
Field
Return the value that should be shown for this field on render of a bound form, given the submitted POST data for the field and the initial data, if any. For most fields, this will simply be data; FileFields need to handle it a bit differently.
def bound_data(self, data, initial):
"""
Return the value that should be shown for this field on render of a
bound form, given the submitted POST data for the field and the initial
data, if any.
For most fields, this will simply be data; FileFields need to handle it
a bit differently.
"""
if self.disabled:
return initial
return data
def
clean(self, value):
¶
ModelMultipleChoiceField
def clean(self, value):
value = self.prepare_value(value)
if self.required and not value:
raise ValidationError(self.error_messages['required'], code='required')
elif not self.required and not value:
return self.queryset.none()
if not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages['list'], code='list')
qs = self._check_values(value)
# Since this overrides the inherited ModelChoiceField.clean
# we run custom validators here
self.run_validators(value)
return qs
Field
Validate the given value and return its "cleaned" value as an appropriate Python object. Raise ValidationError for any errors.
def clean(self, value):
"""
Validate the given value and return its "cleaned" value as an
appropriate Python object. Raise ValidationError for any errors.
"""
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
def
get_bound_field(self, form, field_name):
¶
Field
Return a BoundField instance that will be used when accessing the form field in a template.
def get_bound_field(self, form, field_name):
"""
Return a BoundField instance that will be used when accessing the form
field in a template.
"""
return BoundField(form, self, field_name)
def
get_limit_choices_to(self):
¶
ModelChoiceField
Return ``limit_choices_to`` for this form field. If it is a callable, invoke it and return the result.
def get_limit_choices_to(self):
"""
Return ``limit_choices_to`` for this form field.
If it is a callable, invoke it and return the result.
"""
if callable(self.limit_choices_to):
return self.limit_choices_to()
return self.limit_choices_to
def
has_changed(self, initial, data):
¶
ModelMultipleChoiceField
def has_changed(self, initial, data):
if self.disabled:
return False
if initial is None:
initial = []
if data is None:
data = []
if len(initial) != len(data):
return True
initial_set = {str(value) for value in self.prepare_value(initial)}
data_set = {str(value) for value in data}
return data_set != initial_set
ModelChoiceField
def has_changed(self, initial, data):
if self.disabled:
return False
initial_value = initial if initial is not None else ''
data_value = data if data is not None else ''
return str(self.prepare_value(initial_value)) != str(data_value)
Field
Return True if data differs from initial.
def has_changed(self, initial, data):
"""Return True if data differs from initial."""
# Always return False if the field is disabled since self.bound_data
# always uses the initial value in this case.
if self.disabled:
return False
try:
data = self.to_python(data)
if hasattr(self, '_coerce'):
return self._coerce(data) != self._coerce(initial)
except ValidationError:
return True
# For purposes of seeing whether something has changed, None is
# the same as an empty string, if the data or initial value we get
# is None, replace it with ''.
initial_value = initial if initial is not None else ''
data_value = data if data is not None else ''
return initial_value != data_value
def
label_from_instance(self, obj):
¶
ModelChoiceField
Convert objects into strings and generate the labels for the choices presented by this object. Subclasses can override this method to customize the display of the choices.
def label_from_instance(self, obj):
"""
Convert objects into strings and generate the labels for the choices
presented by this object. Subclasses can override this method to
customize the display of the choices.
"""
return str(obj)
def
prepare_value(self, value):
¶
ModelMultipleChoiceField
def prepare_value(self, value):
if (hasattr(value, '__iter__') and
not isinstance(value, str) and
not hasattr(value, '_meta')):
prepare_value = super().prepare_value
return [prepare_value(v) for v in value]
return super().prepare_value(value)
ModelChoiceField
def prepare_value(self, value):
if hasattr(value, '_meta'):
if self.to_field_name:
return value.serializable_value(self.to_field_name)
else:
return value.pk
return super().prepare_value(value)
Field
def prepare_value(self, value):
return value
def
run_validators(self, value):
¶
Field
def run_validators(self, value):
if value in self.empty_values:
return
errors = []
for v in self.validators:
try:
v(value)
except ValidationError as e:
if hasattr(e, 'code') and e.code in self.error_messages:
e.message = self.error_messages[e.code]
errors.extend(e.error_list)
if errors:
raise ValidationError(errors)
def
to_python(self, value):
¶
ModelMultipleChoiceField
def to_python(self, value):
if not value:
return []
return list(self._check_values(value))
ModelChoiceField
def to_python(self, value):
if value in self.empty_values:
return None
try:
key = self.to_field_name or 'pk'
if isinstance(value, self.queryset.model):
value = getattr(value, key)
value = self.queryset.get(**{key: value})
except (ValueError, TypeError, self.queryset.model.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
return value
ChoiceField
Return a string.
def to_python(self, value):
"""Return a string."""
if value in self.empty_values:
return ''
return str(value)
Field
def to_python(self, value):
return value
def
valid_value(self, value):
¶
ChoiceField
Check to see if the provided value is a valid choice.
def valid_value(self, value):
"""Check to see if the provided value is a valid choice."""
text_value = str(value)
for k, v in self.choices:
if isinstance(v, (list, tuple)):
# This is an optgroup, so look inside the group for options
for k2, v2 in v:
if value == k2 or text_value == str(k2):
return True
else:
if value == k or text_value == str(k):
return True
return False
def
validate(self, value):
¶
ModelChoiceField
def validate(self, value):
return Field.validate(self, value)
ChoiceField
Validate that the input is in self.choices.
def validate(self, value):
"""Validate that the input is in self.choices."""
super().validate(value)
if value and not self.valid_value(value):
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
params={'value': value},
)
Field
def validate(self, value):
if value in self.empty_values and self.required:
raise ValidationError(self.error_messages['required'], code='required')
def
widget_attrs(self, widget):
¶
Field
Given a Widget instance (*not* a Widget class), return a dictionary of any HTML attributes that should be added to the Widget, based on this Field.
def widget_attrs(self, widget):
"""
Given a Widget instance (*not* a Widget class), return a dictionary of
any HTML attributes that should be added to the Widget, based on this
Field.
"""
return {}