diff --git a/AUTHORS b/AUTHORS index 7e620f89a67..75ad94ec1ff 100644 --- a/AUTHORS +++ b/AUTHORS @@ -89,6 +89,7 @@ answer newbie questions, and generally made Django that much better: David Avsajanishvili Mike Axiak Niran Babalola + Christopher Babiak Vitaly Babiy Morten Bagai Jeff Balogh diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 372c0f440b1..f8320117f74 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -665,10 +665,6 @@ class ChoiceFieldRenderer(object): self.attrs = attrs self.choices = choices - def __iter__(self): - for i, choice in enumerate(self.choices): - yield self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, i) - def __getitem__(self, idx): choice = self.choices[idx] # Let the IndexError propogate return self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, idx) @@ -685,8 +681,23 @@ class ChoiceFieldRenderer(object): id_ = self.attrs.get('id', None) start_tag = format_html('
    ', id_) if id_ else '
      ' output = [start_tag] - for widget in self: - output.append(format_html('
    • {0}
    • ', force_text(widget))) + 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('
    • {0}{1}
    • ', 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('
    • {0}
    • ', force_text(w))) output.append('
    ') return mark_safe('\n'.join(output)) diff --git a/tests/forms_tests/tests/test_widgets.py b/tests/forms_tests/tests/test_widgets.py index 033bc7a0359..2d667791e89 100644 --- a/tests/forms_tests/tests/test_widgets.py +++ b/tests/forms_tests/tests/test_widgets.py @@ -695,6 +695,37 @@ beatle J R Ringo False""")
  • +
""") + + def test_nested_choices(self): + # Choices can be nested for radio buttons: + w = RadioSelect() + w.choices=(('unknown', 'Unknown'), ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), ('Video', (('vhs', 'VHS'), ('dvd', 'DVD')))) + self.assertHTMLEqual(w.render('nestchoice', 'dvd', attrs={'id':'media'}), """
    +
  • +
  • Audio
      +
    • +
    • +
  • +
  • Video
      +
    • +
    • +
  • +
""") + + # Choices can be nested for checkboxes: + w = CheckboxSelectMultiple() + w.choices=(('unknown', 'Unknown'), ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), ('Video', (('vhs', 'VHS'), ('dvd', 'DVD')))) + self.assertHTMLEqual(w.render('nestchoice', ('vinyl', 'dvd'), attrs={'id':'media'}), """
    +
  • +
  • Audio
      +
    • +
    • +
  • +
  • Video
      +
    • +
    • +
""") def test_checkboxselectmultiple(self):