Commit 08bec4fb authored by Adrian Holovaty's avatar Adrian Holovaty
Browse files

Changed BoundField.subwidgets() to return SubWidget objects instead of...

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
parent 0920165b
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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):
        """
+18 −2
Original line number Diff line number Diff line
@@ -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'>.
+35 −2
Original line number Diff line number Diff line
@@ -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``
~~~~~~~~~~~~~~~~~~~~~~~~~~
+2 −2
Original line number Diff line number Diff line
@@ -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: