diff --git a/django/forms/models.py b/django/forms/models.py index 0684199db54..d05931ab6e3 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -1126,6 +1126,20 @@ class InlineForeignKeyField(Field): return False +class ModelChoiceIteratorValue: + def __init__(self, value, instance): + self.value = value + self.instance = instance + + def __str__(self): + return str(self.value) + + def __eq__(self, other): + if isinstance(other, ModelChoiceIteratorValue): + other = other.value + return self.value == other + + class ModelChoiceIterator: def __init__(self, field): self.field = field @@ -1151,7 +1165,10 @@ class ModelChoiceIterator: return self.field.empty_label is not None or self.queryset.exists() def choice(self, obj): - return (self.field.prepare_value(obj), self.field.label_from_instance(obj)) + return ( + ModelChoiceIteratorValue(self.field.prepare_value(obj), obj), + self.field.label_from_instance(obj), + ) class ModelChoiceField(ChoiceField): diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 0a2e13c85db..a74980a845f 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -1144,7 +1144,7 @@ method:: Both ``ModelChoiceField`` and ``ModelMultipleChoiceField`` have an ``iterator`` attribute which specifies the class used to iterate over the queryset when -generating choices. +generating choices. See :ref:`iterating-relationship-choices` for details. ``ModelChoiceField`` -------------------- @@ -1285,8 +1285,73 @@ generating choices. Same as :class:`ModelChoiceField.iterator`. +.. _iterating-relationship-choices: + +Iterating relationship choices +------------------------------ + +By default, :class:`ModelChoiceField` and :class:`ModelMultipleChoiceField` use +:class:`ModelChoiceIterator` to generate their field ``choices``. + +When iterated, ``ModelChoiceIterator`` yields 2-tuple choices containing +:class:`ModelChoiceIteratorValue` instances as the first ``value`` element in +each choice. ``ModelChoiceIteratorValue`` wraps the choice value whilst +maintaining a reference to the source model instance that can be used in custom +widget implementations, for example, to add `data-* attributes`_ to +``