summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2011-12-07 23:08:27 +0000
committerAdrian Holovaty <adrian@holovaty.com>2011-12-07 23:08:27 +0000
commit08bec4fbc10ca5638ad22f20a753ec5e8d92eb0e (patch)
tree05bde9737e73fa887ccf8e6ce524007557a2ea35
parent0920165bc26bd55131462befc234ce7993a744ba (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.py8
-rw-r--r--django/forms/widgets.py20
-rw-r--r--docs/ref/forms/widgets.txt37
-rw-r--r--tests/regressiontests/forms/tests/forms.py4
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: