Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3064 -- newforms: Added <label> support through BoundField.lab…

…el_tag() method. Also added BoundField.verbose_name and added/updated unit tests. Thanks, SmileyChris

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4130 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit bb45c394a6d65d3aa1bd1adfd9417a2e4ded532b 1 parent 3d89f26
Adrian Holovaty authored November 29, 2006
21  django/newforms/forms.py
@@ -3,6 +3,7 @@
3 3
 """
4 4
 
5 5
 from django.utils.datastructures import SortedDict
  6
+from django.utils.html import escape
6 7
 from fields import Field
7 8
 from widgets import TextInput, Textarea
8 9
 from util import ErrorDict, ErrorList, ValidationError
@@ -81,7 +82,7 @@ def as_table(self):
81 82
             bf = BoundField(self, field, name)
82 83
             if bf.errors:
83 84
                 output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors)
84  
-            output.append(u'<tr><td>%s:</td><td>%s</td></tr>' % (bf.label, bf))
  85
+            output.append(u'<tr><td>%s</td><td>%s</td></tr>' % (bf.label_tag(bf.verbose_name+':'), bf))
85 86
         return u'\n'.join(output)
86 87
 
87 88
     def as_ul(self):
@@ -95,7 +96,7 @@ def as_ul(self):
95 96
             line = u'<li>'
96 97
             if bf.errors:
97 98
                 line += str(bf.errors)
98  
-            line += u'%s: %s</li>' % (bf.label, bf)
  99
+            line += u'%s %s</li>' % (bf.label_tag(bf.verbose_name+':'), bf)
99 100
             output.append(line)
100 101
         return u'\n'.join(output)
101 102
 
@@ -190,9 +191,21 @@ def as_textarea(self, attrs=None):
190 191
         "Returns a string of HTML for representing this as a <textarea>."
191 192
         return self.as_widget(Textarea(), attrs)
192 193
 
193  
-    def _label(self):
  194
+    def _verbose_name(self):
194 195
         return pretty_name(self._name)
195  
-    label = property(_label)
  196
+    verbose_name = property(_verbose_name)
  197
+
  198
+    def label_tag(self, contents=None):
  199
+        """
  200
+        Wraps the given contents in a <label>, if the field has an ID attribute.
  201
+        Does not HTML-escape the contents. If contents aren't given, uses the
  202
+        field's HTML-escaped verbose_name.
  203
+        """
  204
+        contents = contents or escape(self.verbose_name)
  205
+        id_ = self._field.widget.attrs.get('id') or self.auto_id
  206
+        if id_:
  207
+            contents = '<label for="%s">%s</label>' % (id_, contents)
  208
+        return contents
196 209
 
197 210
     def _auto_id(self):
198 211
         """
76  tests/regressiontests/forms/tests.py
@@ -1251,20 +1251,25 @@
1251 1251
 
1252 1252
 "auto_id" tells the Form to add an "id" attribute to each form element.
1253 1253
 If it's a string that contains '%s', Django will use that as a format string
1254  
-into which the field's name will be inserted.
  1254
+into which the field's name will be inserted. It will also put a <label> around
  1255
+the human-readable labels for a field.
1255 1256
 >>> p = Person(auto_id='id_%s')
1256 1257
 >>> print p.as_ul()
1257  
-<li>First name: <input type="text" name="first_name" id="id_first_name" /></li>
1258  
-<li>Last name: <input type="text" name="last_name" id="id_last_name" /></li>
1259  
-<li>Birthday: <input type="text" name="birthday" id="id_birthday" /></li>
  1258
+<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
  1259
+<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
  1260
+<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li>
  1261
+>>> print p.as_table()
  1262
+<tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
  1263
+<tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
  1264
+<tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr>
1260 1265
 
1261 1266
 If auto_id is any True value whose str() does not contain '%s', the "id"
1262 1267
 attribute will be the name of the field.
1263 1268
 >>> p = Person(auto_id=True)
1264 1269
 >>> print p.as_ul()
1265  
-<li>First name: <input type="text" name="first_name" id="first_name" /></li>
1266  
-<li>Last name: <input type="text" name="last_name" id="last_name" /></li>
1267  
-<li>Birthday: <input type="text" name="birthday" id="birthday" /></li>
  1270
+<li><label for="first_name">First name:</label> <input type="text" name="first_name" id="first_name" /></li>
  1271
+<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
  1272
+<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>
1268 1273
 
1269 1274
 If auto_id is any False value, an "id" attribute won't be output unless it
1270 1275
 was manually entered.
@@ -1275,14 +1280,14 @@
1275 1280
 <li>Birthday: <input type="text" name="birthday" /></li>
1276 1281
 
1277 1282
 In this example, auto_id is False, but the "id" attribute for the "first_name"
1278  
-field is given.
  1283
+field is given. Also note that field gets a <label>, while the others don't.
1279 1284
 >>> class PersonNew(Form):
1280 1285
 ...     first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
1281 1286
 ...     last_name = CharField()
1282 1287
 ...     birthday = DateField()
1283 1288
 >>> p = PersonNew(auto_id=False)
1284 1289
 >>> print p.as_ul()
1285  
-<li>First name: <input type="text" id="first_name_id" name="first_name" /></li>
  1290
+<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
1286 1291
 <li>Last name: <input type="text" name="last_name" /></li>
1287 1292
 <li>Birthday: <input type="text" name="birthday" /></li>
1288 1293
 
@@ -1290,9 +1295,9 @@
1290 1295
 attribute in the Form gets precedence.
1291 1296
 >>> p = PersonNew(auto_id=True)
1292 1297
 >>> print p.as_ul()
1293  
-<li>First name: <input type="text" id="first_name_id" name="first_name" /></li>
1294  
-<li>Last name: <input type="text" name="last_name" id="last_name" /></li>
1295  
-<li>Birthday: <input type="text" name="birthday" id="birthday" /></li>
  1298
+<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
  1299
+<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
  1300
+<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>
1296 1301
 
1297 1302
 >>> class SignupForm(Form):
1298 1303
 ...     email = EmailField()
@@ -1606,10 +1611,57 @@
1606 1611
 <input type="submit" />
1607 1612
 </form>
1608 1613
 
  1614
+Use form.[field].verbose_name to output a field's "verbose name" -- its field
  1615
+name with underscores converted to spaces, and the initial letter capitalized.
  1616
+>>> t = Template('''<form action="">
  1617
+... <p><label>{{ form.username.verbose_name }}: {{ form.username }}</label></p>
  1618
+... <p><label>{{ form.password1.verbose_name }}: {{ form.password1 }}</label></p>
  1619
+... <p><label>{{ form.password2.verbose_name }}: {{ form.password2 }}</label></p>
  1620
+... <input type="submit" />
  1621
+... </form>''')
  1622
+>>> print t.render(Context({'form': UserRegistration()}))
  1623
+<form action="">
  1624
+<p><label>Username: <input type="text" name="username" /></label></p>
  1625
+<p><label>Password1: <input type="password" name="password1" /></label></p>
  1626
+<p><label>Password2: <input type="password" name="password2" /></label></p>
  1627
+<input type="submit" />
  1628
+</form>
  1629
+
  1630
+User form.[field].label_tag to output a field's verbose_name with a <label>
  1631
+tag wrapped around it, but *only* if the given field has an "id" attribute.
  1632
+Recall from above that passing the "auto_id" argument to a Form gives each
  1633
+field an "id" attribute.
  1634
+>>> t = Template('''<form action="">
  1635
+... <p>{{ form.username.label_tag }}: {{ form.username }}</p>
  1636
+... <p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
  1637
+... <p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
  1638
+... <input type="submit" />
  1639
+... </form>''')
  1640
+>>> print t.render(Context({'form': UserRegistration()}))
  1641
+<form action="">
  1642
+<p>Username: <input type="text" name="username" /></p>
  1643
+<p>Password1: <input type="password" name="password1" /></p>
  1644
+<p>Password2: <input type="password" name="password2" /></p>
  1645
+<input type="submit" />
  1646
+</form>
  1647
+>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
  1648
+<form action="">
  1649
+<p><label for="id_username">Username</label>: <input type="text" name="username" id="id_username" /></p>
  1650
+<p><label for="id_password1">Password1</label>: <input type="password" name="password1" id="id_password1" /></p>
  1651
+<p><label for="id_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p>
  1652
+<input type="submit" />
  1653
+</form>
  1654
+
1609 1655
 To display the errors that aren't associated with a particular field -- e.g.,
1610 1656
 the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
1611 1657
 template. If used on its own, it is displayed as a <ul> (or an empty string, if
1612 1658
 the list of errors is empty). You can also use it in {% if %} statements.
  1659
+>>> t = Template('''<form action="">
  1660
+... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
  1661
+... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
  1662
+... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
  1663
+... <input type="submit" />
  1664
+... </form>''')
1613 1665
 >>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
1614 1666
 <form action="">
1615 1667
 <p><label>Your username: <input type="text" name="username" value="django" /></label></p>

0 notes on commit bb45c39

Please sign in to comment.
Something went wrong with that request. Please try again.