diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index 3ffb85e..b6d5bde 100644
a
|
b
|
class AdminField(object):
|
125 | 125 | contents = conditional_escape(force_text(self.field.label)) |
126 | 126 | if self.is_checkbox: |
127 | 127 | classes.append('vCheckboxLabel') |
128 | | else: |
129 | | contents += ':' |
| 128 | |
130 | 129 | if self.field.field.required: |
131 | 130 | classes.append('required') |
132 | 131 | if not self.is_first: |
133 | 132 | classes.append('inline') |
134 | 133 | attrs = {'class': ' '.join(classes)} if classes else {} |
135 | | return self.field.label_tag(contents=mark_safe(contents), attrs=attrs) |
| 134 | # checkboxes should not have a label suffix as the checkbox appears |
| 135 | # to the left of the label. |
| 136 | return self.field.label_tag(contents=mark_safe(contents), attrs=attrs, |
| 137 | label_suffix='' if self.is_checkbox else None) |
136 | 138 | |
137 | 139 | def errors(self): |
138 | 140 | return mark_safe(self.field.errors.as_ul()) |
diff --git a/django/forms/forms.py b/django/forms/forms.py
index e144eb6..ad5daf4 100644
a
|
b
|
class BoundField(object):
|
509 | 509 | ) |
510 | 510 | return self.field.prepare_value(data) |
511 | 511 | |
512 | | def label_tag(self, contents=None, attrs=None): |
| 512 | def label_tag(self, contents=None, attrs=None, label_suffix=None): |
513 | 513 | """ |
514 | 514 | Wraps the given contents in a <label>, if the field has an ID attribute. |
515 | 515 | contents should be 'mark_safe'd to avoid HTML escaping. If contents |
516 | 516 | aren't given, uses the field's HTML-escaped label. |
517 | 517 | |
518 | 518 | If attrs are given, they're used as HTML attributes on the <label> tag. |
| 519 | |
| 520 | label_suffix allows overriding the form's label_suffix. |
519 | 521 | """ |
520 | 522 | contents = contents or self.label |
521 | 523 | # Only add the suffix if the label does not end in punctuation. |
522 | 524 | # Translators: If found as last label character, these punctuation |
523 | 525 | # characters will prevent the default label_suffix to be appended to the label |
524 | | if self.form.label_suffix and contents and contents[-1] not in _(':?.!'): |
525 | | contents = format_html('{0}{1}', contents, self.form.label_suffix) |
| 526 | label_suffix = label_suffix if label_suffix is not None else self.form.label_suffix |
| 527 | if label_suffix and contents and contents[-1] not in _(':?.!'): |
| 528 | contents = format_html('{0}{1}', contents, label_suffix) |
526 | 529 | widget = self.field.widget |
527 | 530 | id_ = widget.attrs.get('id') or self.auto_id |
528 | 531 | if id_: |
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 7c1601d..46a9c39 100644
a
|
b
|
Note that the label suffix is added only if the last character of the
|
527 | 527 | label isn't a punctuation character (in English, those are ``.``, ``!``, ``?`` |
528 | 528 | or ``:``). |
529 | 529 | |
| 530 | .. versionadded:: 1.6 |
| 531 | |
| 532 | You can also customize the ``label_suffix`` on a per-field basis using the |
| 533 | ``label_suffix`` parameter to :meth:`~django.forms.BoundField.label_tag`. |
| 534 | |
530 | 535 | Notes on field ordering |
531 | 536 | ~~~~~~~~~~~~~~~~~~~~~~~ |
532 | 537 | |
… |
… |
when printed::
|
653 | 658 | >>> str(f['subject'].errors) |
654 | 659 | '' |
655 | 660 | |
656 | | .. method:: BoundField.label_tag(contents=None, attrs=None) |
| 661 | .. method:: BoundField.label_tag(contents=None, attrs=None, label_suffix=None) |
657 | 662 | |
658 | 663 | To separately render the label tag of a form field, you can call its |
659 | 664 | ``label_tag`` method:: |
… |
… |
additional attributes for the ``<label>`` tag.
|
671 | 676 | The label now includes the form's :attr:`~django.forms.Form.label_suffix` |
672 | 677 | (a colon, by default). |
673 | 678 | |
| 679 | .. versionadded:: 1.6 |
| 680 | |
| 681 | The optional ``label_suffix`` parameter allows you to override the form's |
| 682 | :attr:`~django.forms.Form.label_suffix`. For example, you can use an empty |
| 683 | string to hide the label on selected fields. |
| 684 | |
674 | 685 | .. method:: BoundField.css_classes() |
675 | 686 | |
676 | 687 | When you use Django's rendering shortcuts, CSS classes are used to |
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index 73b48ed..355b107 100644
a
|
b
|
will render something like:
|
664 | 664 | <label for="id_my_field">My Field:</label> <input id="id_my_field" type="text" name="my_field" /> |
665 | 665 | |
666 | 666 | If you want to keep the current behavior of rendering ``label_tag`` without |
667 | | the ``label_suffix``, instantiate the form ``label_suffix=''``. |
| 667 | the ``label_suffix``, instantiate the form ``label_suffix=''``. You can also |
| 668 | customize the ``label_suffix`` on a per-field basis using the new |
| 669 | ``label_suffix`` parameter on :meth:`~django.forms.BoundField.label_tag`. |
668 | 670 | |
669 | 671 | Admin views ``_changelist_filters`` GET parameter |
670 | 672 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
diff --git a/tests/admin_util/tests.py b/tests/admin_util/tests.py
index 637f643..4a9a203 100644
a
|
b
|
class UtilTests(SimpleTestCase):
|
301 | 301 | self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
302 | 302 | '<label for="id_text" class="required inline"><i>text</i>:</label>') |
303 | 303 | self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), |
304 | | '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i>:</label>') |
| 304 | '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>') |
305 | 305 | |
306 | 306 | # normal strings needs to be escaped |
307 | 307 | class MyForm(forms.Form): |
… |
… |
class UtilTests(SimpleTestCase):
|
312 | 312 | self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
313 | 313 | '<label for="id_text" class="required inline">&text:</label>') |
314 | 314 | self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), |
315 | | '<label for="id_cb" class="vCheckboxLabel required inline">&cb:</label>') |
| 315 | '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') |
316 | 316 | |
317 | 317 | def test_flatten_fieldsets(self): |
318 | 318 | """ |
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 633fde5..c771812 100644
a
|
b
|
class FormsTestCase(TestCase):
|
1870 | 1870 | boundfield = SomeForm()['field'] |
1871 | 1871 | |
1872 | 1872 | self.assertHTMLEqual(boundfield.label_tag(), '<label for="id_field"></label>') |
| 1873 | |
| 1874 | def test_label_tag_override(self): |
| 1875 | """ |
| 1876 | BoundField label_suffix (if provided) overrides Form label_suffix |
| 1877 | """ |
| 1878 | class SomeForm(Form): |
| 1879 | field = CharField() |
| 1880 | boundfield = SomeForm(label_suffix='!')['field'] |
| 1881 | |
| 1882 | self.assertHTMLEqual(boundfield.label_tag(label_suffix='$'), '<label for="id_field">Field$</label>') |