Fixed #18134 -- BoundField.label_tag now includes the form's label_suffix
There was an inconsistency between how the label_tag for forms were generated depending on which method was used: as_p, as_ul and as_table contained code to append the label_suffix where as label_tag called on a form field directly did NOT append the label_suffix. The code for appending the label_suffix has been moved in to the label_tag code of the field and the HTML generation code for as_p, as_ul and as_table now calls this code as well. This is a backwards incompatible change because users who have added the label_suffix manually in their templates may now get double label_suffix characters in their forms.
This commit is contained in:
parent
a643e4d200
commit
584bd14dcf
|
@ -170,11 +170,6 @@ class BaseForm(object):
|
|||
|
||||
if bf.label:
|
||||
label = conditional_escape(force_text(bf.label))
|
||||
# Only add the suffix if the label does not end in
|
||||
# punctuation.
|
||||
if self.label_suffix:
|
||||
if label[-1] not in ':?.!':
|
||||
label = format_html('{0}{1}', label, self.label_suffix)
|
||||
label = bf.label_tag(label) or ''
|
||||
else:
|
||||
label = ''
|
||||
|
@ -522,6 +517,10 @@ class BoundField(object):
|
|||
If attrs are given, they're used as HTML attributes on the <label> tag.
|
||||
"""
|
||||
contents = contents or self.label
|
||||
# Only add the suffix if the label does not end in punctuation.
|
||||
if self.form.label_suffix:
|
||||
if contents[-1] not in ':?.!':
|
||||
contents = format_html('{0}{1}', contents, self.form.label_suffix)
|
||||
widget = self.field.widget
|
||||
id_ = widget.attrs.get('id') or self.auto_id
|
||||
if id_:
|
||||
|
|
|
@ -498,6 +498,8 @@ include ``%s`` -- then the library will act as if ``auto_id`` is ``True``.
|
|||
|
||||
By default, ``auto_id`` is set to the string ``'id_%s'``.
|
||||
|
||||
.. attribute:: Form.label_suffix
|
||||
|
||||
Normally, a colon (``:``) will be appended after any label name when a form is
|
||||
rendered. It's possible to change the colon to another character, or omit it
|
||||
entirely, using the ``label_suffix`` parameter::
|
||||
|
@ -650,12 +652,17 @@ To separately render the label tag of a form field, you can call its
|
|||
|
||||
>>> f = ContactForm(data)
|
||||
>>> print(f['message'].label_tag())
|
||||
<label for="id_message">Message</label>
|
||||
<label for="id_message">Message:</label>
|
||||
|
||||
Optionally, you can provide the ``contents`` parameter which will replace the
|
||||
auto-generated label tag. An optional ``attrs`` dictionary may contain
|
||||
additional attributes for the ``<label>`` tag.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
The label now includes the form's :attr:`~django.forms.Form.label_suffix`
|
||||
(a semicolon, by default).
|
||||
|
||||
.. method:: BoundField.css_classes()
|
||||
|
||||
When you use Django's rendering shortcuts, CSS classes are used to
|
||||
|
|
|
@ -581,6 +581,37 @@ It is still possible to convert the fetched rows to ``Model`` objects
|
|||
lazily by using the :meth:`~django.db.models.query.QuerySet.iterator()`
|
||||
method.
|
||||
|
||||
:meth:`BoundField.label_tag<django.forms.BoundField.label_tag>` now includes the form's :attr:`~django.forms.Form.label_suffix`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is consistent with how methods like
|
||||
:meth:`Form.as_p<django.forms.Form.as_p>` and
|
||||
:meth:`Form.as_ul<django.forms.Form.as_ul>` render labels.
|
||||
|
||||
If you manually render ``label_tag`` in your templates:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ form.my_field.label_tag }}: {{ form.my_field }}
|
||||
|
||||
you'll want to remove the semicolon (or whatever other separator you may be
|
||||
using) to avoid duplicating it when upgrading to Django 1.6. The following
|
||||
template in Django 1.6 will render identically to the above template in Django
|
||||
1.5, except that the semicolon will appear inside the ``<label>`` element.
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ form.my_field.label_tag }} {{ form.my_field }}
|
||||
|
||||
will render something like:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<label for="id_my_field">My Field:</label> <input id="id_my_field" type="text" name="my_field" />
|
||||
|
||||
If you want to keep the current behavior of rendering ``label_tag`` without
|
||||
the ``label_suffix``, instantiate the form ``label_suffix=''``.
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -302,7 +302,7 @@ loop::
|
|||
{% for field in form %}
|
||||
<div class="fieldWrapper">
|
||||
{{ field.errors }}
|
||||
{{ field.label_tag }}: {{ field }}
|
||||
{{ field.label_tag }} {{ field }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p><input type="submit" value="Send message" /></p>
|
||||
|
@ -316,8 +316,14 @@ attributes, which can be useful in your templates:
|
|||
The label of the field, e.g. ``Email address``.
|
||||
|
||||
``{{ field.label_tag }}``
|
||||
The field's label wrapped in the appropriate HTML ``<label>`` tag,
|
||||
e.g. ``<label for="id_email">Email address</label>``
|
||||
The field's label wrapped in the appropriate HTML ``<label>`` tag.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
This includes the form's :attr:`~django.forms.Form.label_suffix`. For
|
||||
example, the default ``label_suffix`` is a semicolon::
|
||||
|
||||
<label for="id_email">Email address:</label>
|
||||
|
||||
``{{ field.value }}``
|
||||
The value of the field. e.g ``someone@example.com``
|
||||
|
@ -375,7 +381,7 @@ these two methods::
|
|||
{% for field in form.visible_fields %}
|
||||
<div class="fieldWrapper">
|
||||
{{ field.errors }}
|
||||
{{ field.label_tag }}: {{ field }}
|
||||
{{ field.label_tag }} {{ field }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p><input type="submit" value="Send message" /></p>
|
||||
|
@ -403,7 +409,7 @@ using the :ttag:`include` tag to reuse it in other templates::
|
|||
{% for field in form %}
|
||||
<div class="fieldWrapper">
|
||||
{{ field.errors }}
|
||||
{{ field.label_tag }}: {{ field }}
|
||||
{{ field.label_tag }} {{ field }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -907,7 +907,7 @@ Third, you can manually render each field::
|
|||
{{ formset.management_form }}
|
||||
{% for form in formset %}
|
||||
{% for field in form %}
|
||||
{{ field.label_tag }}: {{ field }}
|
||||
{{ field.label_tag }} {{ field }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</form>
|
||||
|
|
|
@ -301,7 +301,7 @@ class UtilTests(SimpleTestCase):
|
|||
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
|
||||
'<label for="id_text" class="required inline"><i>text</i>:</label>')
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>')
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i>:</label>')
|
||||
|
||||
# normal strings needs to be escaped
|
||||
class MyForm(forms.Form):
|
||||
|
@ -312,7 +312,7 @@ class UtilTests(SimpleTestCase):
|
|||
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
|
||||
'<label for="id_text" class="required inline">&text:</label>')
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>')
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline">&cb:</label>')
|
||||
|
||||
def test_flatten_fieldsets(self):
|
||||
"""
|
||||
|
|
|
@ -1589,9 +1589,9 @@ class FormsTestCase(TestCase):
|
|||
# Recall from above that passing the "auto_id" argument to a Form gives each
|
||||
# field an "id" attribute.
|
||||
t = Template('''<form action="">
|
||||
<p>{{ form.username.label_tag }}: {{ form.username }}</p>
|
||||
<p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
|
||||
<p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
|
||||
<p>{{ form.username.label_tag }} {{ form.username }}</p>
|
||||
<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
|
||||
<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
|
||||
<input type="submit" />
|
||||
</form>''')
|
||||
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
|
||||
|
@ -1601,18 +1601,18 @@ class FormsTestCase(TestCase):
|
|||
<input type="submit" />
|
||||
</form>""")
|
||||
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form action="">
|
||||
<p><label for="id_username">Username</label>: <input id="id_username" type="text" name="username" maxlength="10" /></p>
|
||||
<p><label for="id_password1">Password1</label>: <input type="password" name="password1" id="id_password1" /></p>
|
||||
<p><label for="id_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p>
|
||||
<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>
|
||||
<p><label for="id_password1">Password1:</label> <input type="password" name="password1" id="id_password1" /></p>
|
||||
<p><label for="id_password2">Password2:</label> <input type="password" name="password2" id="id_password2" /></p>
|
||||
<input type="submit" />
|
||||
</form>""")
|
||||
|
||||
# User form.[field].help_text to output a field's help text. If the given field
|
||||
# does not have help text, nothing will be output.
|
||||
t = Template('''<form action="">
|
||||
<p>{{ form.username.label_tag }}: {{ form.username }}<br />{{ form.username.help_text }}</p>
|
||||
<p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
|
||||
<p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
|
||||
<p>{{ form.username.label_tag }} {{ form.username }}<br />{{ form.username.help_text }}</p>
|
||||
<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
|
||||
<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
|
||||
<input type="submit" />
|
||||
</form>''')
|
||||
self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
|
||||
|
@ -1819,17 +1819,17 @@ class FormsTestCase(TestCase):
|
|||
|
||||
testcases = [ # (args, kwargs, expected)
|
||||
# without anything: just print the <label>
|
||||
((), {}, '<label for="id_field">Field</label>'),
|
||||
((), {}, '<label for="id_field">Field:</label>'),
|
||||
|
||||
# passing just one argument: overrides the field's label
|
||||
(('custom',), {}, '<label for="id_field">custom</label>'),
|
||||
(('custom',), {}, '<label for="id_field">custom:</label>'),
|
||||
|
||||
# the overriden label is escaped
|
||||
(('custom&',), {}, '<label for="id_field">custom&</label>'),
|
||||
((mark_safe('custom&'),), {}, '<label for="id_field">custom&</label>'),
|
||||
(('custom&',), {}, '<label for="id_field">custom&:</label>'),
|
||||
((mark_safe('custom&'),), {}, '<label for="id_field">custom&:</label>'),
|
||||
|
||||
# Passing attrs to add extra attributes on the <label>
|
||||
((), {'attrs': {'class': 'pretty'}}, '<label for="id_field" class="pretty">Field</label>')
|
||||
((), {'attrs': {'class': 'pretty'}}, '<label for="id_field" class="pretty">Field:</label>')
|
||||
]
|
||||
|
||||
for args, kwargs, expected in testcases:
|
||||
|
@ -1844,8 +1844,8 @@ class FormsTestCase(TestCase):
|
|||
field = CharField()
|
||||
boundfield = SomeForm(auto_id='')['field']
|
||||
|
||||
self.assertHTMLEqual(boundfield.label_tag(), 'Field')
|
||||
self.assertHTMLEqual(boundfield.label_tag('Custom&'), 'Custom&')
|
||||
self.assertHTMLEqual(boundfield.label_tag(), 'Field:')
|
||||
self.assertHTMLEqual(boundfield.label_tag('Custom&'), 'Custom&:')
|
||||
|
||||
def test_boundfield_label_tag_custom_widget_id_for_label(self):
|
||||
class CustomIdForLabelTextInput(TextInput):
|
||||
|
@ -1861,5 +1861,5 @@ class FormsTestCase(TestCase):
|
|||
empty = CharField(widget=EmptyIdForLabelTextInput)
|
||||
|
||||
form = SomeForm()
|
||||
self.assertHTMLEqual(form['custom'].label_tag(), '<label for="custom_id_custom">Custom</label>')
|
||||
self.assertHTMLEqual(form['empty'].label_tag(), '<label>Empty</label>')
|
||||
self.assertHTMLEqual(form['custom'].label_tag(), '<label for="custom_id_custom">Custom:</label>')
|
||||
self.assertHTMLEqual(form['empty'].label_tag(), '<label>Empty:</label>')
|
||||
|
|
|
@ -45,8 +45,8 @@ class FormsRegressionsTestCase(TransRealMixin, TestCase):
|
|||
field_2 = CharField(max_length=10, label=ugettext_lazy('field_2'), widget=TextInput(attrs={'id': 'field_2_id'}))
|
||||
|
||||
f = SomeForm()
|
||||
self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1</label>')
|
||||
self.assertHTMLEqual(f['field_2'].label_tag(), '<label for="field_2_id">field_2</label>')
|
||||
self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>')
|
||||
self.assertHTMLEqual(f['field_2'].label_tag(), '<label for="field_2_id">field_2:</label>')
|
||||
|
||||
# Unicode decoding problems...
|
||||
GENDERS = (('\xc5', 'En tied\xe4'), ('\xf8', 'Mies'), ('\xdf', 'Nainen'))
|
||||
|
|
Loading…
Reference in New Issue