From be0bab1bb8da80402248cd1fa22fd4cc09b34fe7 Mon Sep 17 00:00:00 2001 From: Claude Paroz <claude@2xlibre.net> Date: Sat, 25 May 2013 15:18:48 +0200 Subject: [PATCH] Fixed #11725 -- Made possible to create widget label tag without "for" Thanks Denis Martinez for the report and initial patch, and Sergey Kolosov for bringing the patch up to date. --- django/forms/forms.py | 7 ++++--- tests/admin_util/tests.py | 23 +++++++++++------------ tests/forms_tests/tests/test_forms.py | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/django/forms/forms.py b/django/forms/forms.py index fece2158ac..2c173a45dc 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -525,10 +525,11 @@ class BoundField(object): widget = self.field.widget id_ = widget.attrs.get('id') or self.auto_id if id_: + id_for_label = widget.id_for_label(id_) + if id_for_label: + attrs = dict(attrs or {}, **{'for': id_for_label}) attrs = flatatt(attrs) if attrs else '' - contents = format_html('<label for="{0}"{1}>{2}</label>', - widget.id_for_label(id_), attrs, contents - ) + contents = format_html('<label{0}>{1}</label>', attrs, contents) else: contents = conditional_escape(contents) return mark_safe(contents) diff --git a/tests/admin_util/tests.py b/tests/admin_util/tests.py index 35b7681cbb..4a9a203f50 100644 --- a/tests/admin_util/tests.py +++ b/tests/admin_util/tests.py @@ -11,8 +11,7 @@ from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE from django.contrib.sites.models import Site from django.db import models, DEFAULT_DB_ALIAS from django import forms -from django.test import TestCase -from django.utils import unittest +from django.test import SimpleTestCase, TestCase from django.utils.formats import localize from django.utils.safestring import mark_safe from django.utils import six @@ -82,7 +81,7 @@ class NestedObjectsTests(TestCase): # One for Location, one for Guest, and no query for EventGuide n.collect(objs) -class UtilTests(unittest.TestCase): +class UtilTests(SimpleTestCase): def test_values_from_lookup_field(self): """ Regression test for #12654: lookup_field @@ -151,7 +150,7 @@ class UtilTests(unittest.TestCase): # handling. display_value = display_for_field(None, models.NullBooleanField()) expected = '<img src="%sadmin/img/icon-unknown.gif" alt="None" />' % settings.STATIC_URL - self.assertEqual(display_value, expected) + self.assertHTMLEqual(display_value, expected) display_value = display_for_field(None, models.DecimalField()) self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) @@ -299,10 +298,10 @@ class UtilTests(unittest.TestCase): cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) form = MyForm() - self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), - '<label for="id_text" class="required inline"><i>text</i>:</label>') - self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), - '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>') + 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>') # normal strings needs to be escaped class MyForm(forms.Form): @@ -310,10 +309,10 @@ class UtilTests(unittest.TestCase): cb = forms.BooleanField(label='&cb') form = MyForm() - self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), - '<label for="id_text" class="required inline">&text:</label>') - self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), - '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') + 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>') def test_flatten_fieldsets(self): """ diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index 45e62a492c..f7eb46522f 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -1846,3 +1846,20 @@ class FormsTestCase(TestCase): 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): + def id_for_label(self, id): + return 'custom_' + id + + class EmptyIdForLabelTextInput(TextInput): + def id_for_label(self, id): + return None + + class SomeForm(Form): + custom = CharField(widget=CustomIdForLabelTextInput) + 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>')