#27758: Template widget rendering breaks the AdvancedModelIterator pattern ----------------------------------------+------------------------ Reporter: Jon Dufresne | Owner: nobody Type: Bug | Status: new Component: Forms | Version: 1.11 Severity: Normal | Keywords: Triage Stage: Unreviewed | Has patch: 0 Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | ----------------------------------------+------------------------ Occasionally, when extending `ModelChoiceField` and `ModelMultipleChoiceField` with a custom widget, it is useful for the widget to know the object used to create the value, label pair. This could be used to adding custom HTML attributes to very specific choices.
Historically, a pattern was developed to handle this situation named [http://srcmvn.com/blog/2013/01/15/django-advanced-model-choice-field AdvancedModelChoiceIterator]. The pattern described in the article breaks in 1.11. Firstly, `ChoiceWidget` now always expects a 2-tuple returned by `ModelChoiceIterator.choice()` as it is unpacked in [https://github.com/django/django/blob/a15d81a183e2d85969ed46adb975661515330b16/django/forms/widgets.py#L573 ChoiceWidget.optgroups()]. The usage is [https://docs.djangoproject.com/en/1.10/ref/forms/fields/#django.forms.ChoiceField.choices documented] as requiring a 2-tuple, so maybe this is considered OK. An alternative I considered was returning a wrapped value to hold the object, hoping this would be accessible from `ChoiceWidget.create_option()`. Unfortunately this did not work as the value is eagerly coerced to a string very early in [https://github.com/django/django/blob/a15d81a183e2d85969ed46adb975661515330b16/django/forms/widgets.py#L577 ChoiceWidget.optgroups()]. For example: {{{ class AdvancedChoiceValue: def __init__(self, value, obj): self.value = value self.obj = obj def __str__(self): return str(self.value) class AdvancedChoiceIterator(ModelChoiceIterator): def choice(self, obj): value, label = super().choice(obj) return AdvancedChoiceValue(value, obj), label }}} I think delaying the `force_text()` until checking the selected value would solve this problem. -- Ticket URL: <https://code.djangoproject.com/ticket/27758> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/052.68b0cc347ce49fed1fd2e566dcc0afc4%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.