#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.

Reply via email to