mirror of https://github.com/django/django.git
Fixed #26927 -- Made subwidget iteration pass disabled and required attributes.
This commit is contained in:
parent
aad46c3e37
commit
ac3aaaa740
|
@ -51,6 +51,7 @@ class BoundField(object):
|
||||||
"""
|
"""
|
||||||
id_ = self.field.widget.attrs.get('id') or self.auto_id
|
id_ = self.field.widget.attrs.get('id') or self.auto_id
|
||||||
attrs = {'id': id_} if id_ else {}
|
attrs = {'id': id_} if id_ else {}
|
||||||
|
attrs = self.build_widget_attrs(attrs)
|
||||||
for subwidget in self.field.widget.subwidgets(self.html_name, self.value(), attrs):
|
for subwidget in self.field.widget.subwidgets(self.html_name, self.value(), attrs):
|
||||||
yield subwidget
|
yield subwidget
|
||||||
|
|
||||||
|
@ -85,10 +86,7 @@ class BoundField(object):
|
||||||
widget.is_localized = True
|
widget.is_localized = True
|
||||||
|
|
||||||
attrs = attrs or {}
|
attrs = attrs or {}
|
||||||
if not widget.is_hidden and self.field.required and self.form.use_required_attribute:
|
attrs = self.build_widget_attrs(attrs, widget)
|
||||||
attrs['required'] = True
|
|
||||||
if self.field.disabled:
|
|
||||||
attrs['disabled'] = True
|
|
||||||
auto_id = self.auto_id
|
auto_id = self.auto_id
|
||||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
||||||
if not only_initial:
|
if not only_initial:
|
||||||
|
@ -227,3 +225,13 @@ class BoundField(object):
|
||||||
widget = self.field.widget
|
widget = self.field.widget
|
||||||
id_ = widget.attrs.get('id') or self.auto_id
|
id_ = widget.attrs.get('id') or self.auto_id
|
||||||
return widget.id_for_label(id_)
|
return widget.id_for_label(id_)
|
||||||
|
|
||||||
|
def build_widget_attrs(self, attrs, widget=None):
|
||||||
|
if not widget:
|
||||||
|
widget = self.field.widget
|
||||||
|
attrs = dict(attrs) # Copy attrs to avoid modifying the argument.
|
||||||
|
if not widget.is_hidden and self.field.required and self.form.use_required_attribute:
|
||||||
|
attrs['required'] = True
|
||||||
|
if self.field.disabled:
|
||||||
|
attrs['disabled'] = True
|
||||||
|
return attrs
|
||||||
|
|
|
@ -787,6 +787,13 @@ class CheckboxSelectMultiple(RendererMixin, SelectMultiple):
|
||||||
renderer = CheckboxFieldRenderer
|
renderer = CheckboxFieldRenderer
|
||||||
_empty_value = []
|
_empty_value = []
|
||||||
|
|
||||||
|
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||||
|
attrs = super(CheckboxSelectMultiple, self).build_attrs(extra_attrs, **kwargs)
|
||||||
|
# Remove the 'required' attribute because browser validation would
|
||||||
|
# require all checkboxes to be checked instead of at least one.
|
||||||
|
attrs.pop('required', None)
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class MultiWidget(Widget):
|
class MultiWidget(Widget):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -714,8 +714,10 @@ Selector and checkbox widgets
|
||||||
The outer ``<ul>`` container receives the ``id`` attribute of the widget,
|
The outer ``<ul>`` container receives the ``id`` attribute of the widget,
|
||||||
if defined, or :attr:`BoundField.auto_id` otherwise.
|
if defined, or :attr:`BoundField.auto_id` otherwise.
|
||||||
|
|
||||||
Like :class:`RadioSelect`, you can now loop over the individual checkboxes making
|
Like :class:`RadioSelect`, you can loop over the individual checkboxes for the
|
||||||
up the lists. See the documentation of :class:`RadioSelect` for more details.
|
widget's choices. Unlike :class:`RadioSelect`, the checkboxes won't include the
|
||||||
|
``required`` HTML attribute if the field is required because browser validation
|
||||||
|
would require all checkboxes to be checked instead of at least one.
|
||||||
|
|
||||||
When looping over the checkboxes, the ``label`` and ``input`` tags include
|
When looping over the checkboxes, the ``label`` and ``input`` tags include
|
||||||
``for`` and ``id`` attributes, respectively. Each checkbox has an
|
``for`` and ``id`` attributes, respectively. Each checkbox has an
|
||||||
|
|
|
@ -646,9 +646,9 @@ Java</label></li>
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
t.render(Context({'form': f})),
|
t.render(Context({'form': f})),
|
||||||
"""<div class="myradio"><label for="id_language_0">
|
"""<div class="myradio"><label for="id_language_0">
|
||||||
<input id="id_language_0" name="language" type="radio" value="P" /> Python</label></div>
|
<input id="id_language_0" name="language" type="radio" value="P" required /> Python</label></div>
|
||||||
<div class="myradio"><label for="id_language_1">
|
<div class="myradio"><label for="id_language_1">
|
||||||
<input id="id_language_1" name="language" type="radio" value="J" /> Java</label></div>"""
|
<input id="id_language_1" name="language" type="radio" value="J" required /> Java</label></div>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_form_with_iterable_boundfield(self):
|
def test_form_with_iterable_boundfield(self):
|
||||||
|
@ -661,17 +661,17 @@ Java</label></li>
|
||||||
f = BeatleForm(auto_id=False)
|
f = BeatleForm(auto_id=False)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
'\n'.join(str(bf) for bf in f['name']),
|
'\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="john" required /> John</label>
|
||||||
<label><input type="radio" name="name" value="paul" /> Paul</label>
|
<label><input type="radio" name="name" value="paul" required /> Paul</label>
|
||||||
<label><input type="radio" name="name" value="george" /> George</label>
|
<label><input type="radio" name="name" value="george" required /> George</label>
|
||||||
<label><input type="radio" name="name" value="ringo" /> Ringo</label>"""
|
<label><input type="radio" name="name" value="ringo" required /> Ringo</label>"""
|
||||||
)
|
)
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
'\n'.join('<div>%s</div>' % bf for bf in f['name']),
|
'\n'.join('<div>%s</div>' % bf for bf in f['name']),
|
||||||
"""<div><label><input type="radio" name="name" value="john" /> John</label></div>
|
"""<div><label><input type="radio" name="name" value="john" required /> John</label></div>
|
||||||
<div><label><input type="radio" name="name" value="paul" /> Paul</label></div>
|
<div><label><input type="radio" name="name" value="paul" required /> Paul</label></div>
|
||||||
<div><label><input type="radio" name="name" value="george" /> George</label></div>
|
<div><label><input type="radio" name="name" value="george" required /> George</label></div>
|
||||||
<div><label><input type="radio" name="name" value="ringo" /> Ringo</label></div>"""
|
<div><label><input type="radio" name="name" value="ringo" required /> Ringo</label></div>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_form_with_noniterable_boundfield(self):
|
def test_form_with_noniterable_boundfield(self):
|
||||||
|
@ -680,7 +680,7 @@ Java</label></li>
|
||||||
name = CharField()
|
name = CharField()
|
||||||
|
|
||||||
f = BeatleForm(auto_id=False)
|
f = BeatleForm(auto_id=False)
|
||||||
self.assertHTMLEqual('\n'.join(str(bf) for bf in f['name']), '<input type="text" name="name" />')
|
self.assertHTMLEqual('\n'.join(str(bf) for bf in f['name']), '<input type="text" name="name" required />')
|
||||||
|
|
||||||
def test_boundfield_slice(self):
|
def test_boundfield_slice(self):
|
||||||
class BeatleForm(Form):
|
class BeatleForm(Form):
|
||||||
|
@ -803,18 +803,18 @@ Java</label></li>
|
||||||
|
|
||||||
f = SongForm(auto_id=False)
|
f = SongForm(auto_id=False)
|
||||||
self.assertHTMLEqual(str(f['composers']), """<ul>
|
self.assertHTMLEqual(str(f['composers']), """<ul>
|
||||||
<li><label><input type="checkbox" name="composers" value="J" required /> John Lennon</label></li>
|
<li><label><input type="checkbox" name="composers" value="J" /> John Lennon</label></li>
|
||||||
<li><label><input type="checkbox" name="composers" value="P" required /> Paul McCartney</label></li>
|
<li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
|
||||||
</ul>""")
|
</ul>""")
|
||||||
f = SongForm({'composers': ['J']}, auto_id=False)
|
f = SongForm({'composers': ['J']}, auto_id=False)
|
||||||
self.assertHTMLEqual(str(f['composers']), """<ul>
|
self.assertHTMLEqual(str(f['composers']), """<ul>
|
||||||
<li><label><input checked="checked" type="checkbox" name="composers" value="J" required /> John Lennon</label></li>
|
<li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li>
|
||||||
<li><label><input type="checkbox" name="composers" value="P" required /> Paul McCartney</label></li>
|
<li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
|
||||||
</ul>""")
|
</ul>""")
|
||||||
f = SongForm({'composers': ['J', 'P']}, auto_id=False)
|
f = SongForm({'composers': ['J', 'P']}, auto_id=False)
|
||||||
self.assertHTMLEqual(str(f['composers']), """<ul>
|
self.assertHTMLEqual(str(f['composers']), """<ul>
|
||||||
<li><label><input checked="checked" type="checkbox" name="composers" value="J" required /> John Lennon</label></li>
|
<li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li>
|
||||||
<li><label><input checked="checked" type="checkbox" name="composers" value="P" required /> Paul McCartney</label></li>
|
<li><label><input checked="checked" type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
|
||||||
</ul>""")
|
</ul>""")
|
||||||
# Test iterating on individual checkboxes in a template
|
# Test iterating on individual checkboxes in a template
|
||||||
t = Template('{% for checkbox in form.composers %}<div class="mycheckbox">{{ checkbox }}</div>{% endfor %}')
|
t = Template('{% for checkbox in form.composers %}<div class="mycheckbox">{{ checkbox }}</div>{% endfor %}')
|
||||||
|
@ -839,9 +839,9 @@ Java</label></li>
|
||||||
str(f['composers']),
|
str(f['composers']),
|
||||||
"""<ul id="composers_id">
|
"""<ul id="composers_id">
|
||||||
<li><label for="composers_id_0">
|
<li><label for="composers_id_0">
|
||||||
<input type="checkbox" name="composers" value="J" id="composers_id_0" required /> John Lennon</label></li>
|
<input type="checkbox" name="composers" value="J" id="composers_id_0" /> John Lennon</label></li>
|
||||||
<li><label for="composers_id_1">
|
<li><label for="composers_id_1">
|
||||||
<input type="checkbox" name="composers" value="P" id="composers_id_1" required /> Paul McCartney</label></li>
|
<input type="checkbox" name="composers" value="P" id="composers_id_1" /> Paul McCartney</label></li>
|
||||||
</ul>"""
|
</ul>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue