#22950: Subclassing choice select widgets is a nightmare
----------------------------------------------+----------------------
     Reporter:  Patrick Robertson <django@…>  |      Owner:  nobody
         Type:  Uncategorized                 |     Status:  new
    Component:  Uncategorized                 |    Version:  1.7-rc-1
     Severity:  Normal                        |   Keywords:
 Triage Stage:  Unreviewed                    |  Has patch:  0
Easy pickings:  0                             |      UI/UX:  0
----------------------------------------------+----------------------
 So say I want to change the HTML of a RadioSelect widget from using `<ul>`
 to something like:


 {{{
 <div>
 <label>label</label>
 <input>
 </div>
 }}}


 It sounds pretty simple right? But it looks like I need all of this code,
 which still doesn't work:


 {{{
 class BSChoiceFieldRenderer(widgets.ChoiceFieldRenderer):
     def render(self):
         """
         Outputs a <ul> for this set of choice fields.
         If an id was given to the field, it is applied to the <ul> (each
         item in the list will get an id of `$id_$i`).
         """
         id_ = self.attrs.get('id', None)
         start_tag = format_html('<div id="{0}">', id_) if id_ else '<div>'
         output = [start_tag]
         for i, choice in enumerate(self.choices):
             choice_value, choice_label = choice
             if isinstance(choice_label, (tuple, list)):
                 attrs_plus = self.attrs.copy()
                 if id_:
                     attrs_plus['id'] += '_{0}'.format(i)
                 sub_ul_renderer = ChoiceFieldRenderer(name=self.name,
                                                       value=self.value,
                                                       attrs=attrs_plus,
 choices=choice_label)
                 sub_ul_renderer.choice_input_class =
 self.choice_input_class
                 output.append(format_html('<div>{0}{1}</div>',
 choice_value,
                                           sub_ul_renderer.render()))
             else:
                 w = self.choice_input_class(self.name, self.value,
                                             self.attrs.copy(), choice, i)
                 output.append(format_html('<div>{0}</div>',
 force_text(w)))
         output.append('</div>')
         return mark_safe('\n'.join(output))

 class BSRadioFieldRenderer(BSChoiceFieldRenderer):
     choice_input_class = widgets.RadioChoiceInput

 # Subclass of the RadioSelect widget
 class BSRadioSelect(widgets.RadioSelect):
     renderer = BSRadioFieldRenderer

 ...
 forms.py

 something = forms.ChoiceField(choices=choices, widget=BSRadioSelect())
 }}}


 If I try and put the `render()` method in the `BSRadioFieldRenderer`
 subclass (so as to avoid having to subclass `ChoiceFieldRenderer`) I get
 an error about NoneType not being callable.
 With the code as it stands here, the widget isn't actually rendered, just
 escaped HTML is printed

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22950>
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/083.2167ca9d3ec1ffce8df200ea8f377c7a%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to