Permalink
Browse files

Changed BoundField.subwidgets() to return SubWidget objects instead o…

…f 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
  • Loading branch information...
1 parent 0920165 commit 08bec4fbc10ca5638ad22f20a753ec5e8d92eb0e @adrianholovaty adrianholovaty committed Dec 7, 2011
Showing with 62 additions and 7 deletions.
  1. +7 −1 django/forms/forms.py
  2. +18 −2 django/forms/widgets.py
  3. +35 −2 docs/ref/forms/widgets.txt
  4. +2 −2 tests/regressiontests/forms/tests/forms.py
View
@@ -418,7 +418,13 @@ def __iter__(self):
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):
"""
View
@@ -137,6 +137,22 @@ def __new__(cls, name, bases, attrs):
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 @@ def subwidgets(self, name, value, attrs=None, choices=()):
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 @@ def _has_changed(self, initial, data):
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'>.
View
@@ -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``
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -439,7 +439,7 @@ class BeatleForm(Form):
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 BeatleForm(Form):
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:

0 comments on commit 08bec4f

Please sign in to comment.