diff options
| author | Adrian Holovaty <adrian@holovaty.com> | 2011-12-07 23:08:27 +0000 |
|---|---|---|
| committer | Adrian Holovaty <adrian@holovaty.com> | 2011-12-07 23:08:27 +0000 |
| commit | 08bec4fbc10ca5638ad22f20a753ec5e8d92eb0e (patch) | |
| tree | 05bde9737e73fa887ccf8e6ce524007557a2ea35 | |
| parent | 0920165bc26bd55131462befc234ce7993a744ba (diff) | |
Changed BoundField.subwidgets() to return SubWidget objects instead of rendered strings. This means we can access individual radio buttons' properties in the template (see new docs)
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17175 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | django/forms/forms.py | 8 | ||||
| -rw-r--r-- | django/forms/widgets.py | 20 | ||||
| -rw-r--r-- | docs/ref/forms/widgets.txt | 37 | ||||
| -rw-r--r-- | tests/regressiontests/forms/tests/forms.py | 4 |
4 files changed, 62 insertions, 7 deletions
diff --git a/django/forms/forms.py b/django/forms/forms.py index 7818aac13a..d3f2046779 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -418,7 +418,13 @@ class BoundField(StrAndUnicode): iterate over individual radio buttons in a template. """ for subwidget in self.field.widget.subwidgets(self.html_name, self.value()): - yield self.as_widget(subwidget) + yield subwidget + + def __len__(self): + return len(list(self.__iter__())) + + def __getitem__(self, idx): + return list(self.__iter__())[idx] def _errors(self): """ diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 9c04750fdb..49b148eeca 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -137,6 +137,22 @@ class MediaDefiningClass(type): new_class.media = media_property(new_class) return new_class +class SubWidget(StrAndUnicode): + """ + Some widgets are made of multiple HTML elements -- namely, RadioSelect. + This is a class that represents the "inner" HTML element of a widget. + """ + def __init__(self, parent_widget, name, value, attrs, choices): + self.parent_widget = parent_widget + self.name, self.value = name, value + self.attrs, self.choices = attrs, choices + + def __unicode__(self): + args = [self.name, self.value, self.attrs] + if self.choices: + args.append(self.choices) + return self.parent_widget.render(*args) + class Widget(object): __metaclass__ = MediaDefiningClass is_hidden = False # Determines whether this corresponds to an <input type="hidden">. @@ -163,7 +179,7 @@ class Widget(object): Arguments are the same as for render(). """ - yield self + yield SubWidget(self, name, value, attrs, choices) def render(self, name, value, attrs=None): """ @@ -623,7 +639,7 @@ class SelectMultiple(Select): data_set = set([force_unicode(value) for value in data]) return data_set != initial_set -class RadioInput(StrAndUnicode): +class RadioInput(SubWidget): """ An object used by RadioFieldRenderer that represents a single <input type='radio'>. diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index b657be4c53..ac110c2ee8 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -386,8 +386,41 @@ commonly used groups of widgets: <label><input type="radio" name="beatles" value="ringo" /> Ringo</label> </div> - If you decide not to loop over the radio buttons, they'll be output in a - ``<ul>`` with ``<li>`` tags, as above. + That included the ``<label>`` tags. To get more granular, you can use each + radio button's ``tag`` and ``choice_label`` attributes. For example, this template... + + .. code-block:: html+django + + {% for radio in myform.beatles %} + <label> + {{ radio.choice_label }} + <span class="radio">{{ radio.tag }}</span> + </label> + {% endfor %} + + ...will result in the following HTML: + + .. code-block:: html + + <label> + John + <span class="radio"><input type="radio" name="beatles" value="john" /></span> + </label> + <label> + Paul + <span class="radio"><input type="radio" name="beatles" value="paul" /></span> + </label> + <label> + George + <span class="radio"><input type="radio" name="beatles" value="george" /></span> + </label> + <label> + Ringo + <span class="radio"><input type="radio" name="beatles" value="ringo" /></span> + </label> + + If you decide not to loop over the radio buttons -- e.g., if your template simply includes + ``{{ myform.beatles }}`` -- they'll be output in a ``<ul>`` with ``<li>`` tags, as above. ``CheckboxSelectMultiple`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/regressiontests/forms/tests/forms.py b/tests/regressiontests/forms/tests/forms.py index e456c38a38..4e9cc16f23 100644 --- a/tests/regressiontests/forms/tests/forms.py +++ b/tests/regressiontests/forms/tests/forms.py @@ -439,7 +439,7 @@ class FormsTestCase(TestCase): name = ChoiceField(choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')], widget=RadioSelect) f = BeatleForm(auto_id=False) - self.assertEqual('\n'.join(list(f['name'])), """<label><input type="radio" name="name" value="john" /> John</label> + self.assertEqual('\n'.join([str(bf) for bf in f['name']]), """<label><input type="radio" name="name" value="john" /> John</label> <label><input type="radio" name="name" value="paul" /> Paul</label> <label><input type="radio" name="name" value="george" /> George</label> <label><input type="radio" name="name" value="ringo" /> Ringo</label>""") @@ -454,7 +454,7 @@ class FormsTestCase(TestCase): name = CharField() f = BeatleForm(auto_id=False) - self.assertEqual('\n'.join(list(f['name'])), u'<input type="text" name="name" />') + self.assertEqual('\n'.join([str(bf) for bf in f['name']]), u'<input type="text" name="name" />') def test_forms_with_multiple_choice(self): # MultipleChoiceField is a special case, as its data is required to be a list: |
