Fixed #3064 -- newforms: Added <label> support through BoundField.label_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
This commit is contained in:
parent
3d89f26b08
commit
bb45c394a6
|
@ -3,6 +3,7 @@ Form classes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
from django.utils.html import escape
|
||||||
from fields import Field
|
from fields import Field
|
||||||
from widgets import TextInput, Textarea
|
from widgets import TextInput, Textarea
|
||||||
from util import ErrorDict, ErrorList, ValidationError
|
from util import ErrorDict, ErrorList, ValidationError
|
||||||
|
@ -81,7 +82,7 @@ class Form(object):
|
||||||
bf = BoundField(self, field, name)
|
bf = BoundField(self, field, name)
|
||||||
if bf.errors:
|
if bf.errors:
|
||||||
output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors)
|
output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors)
|
||||||
output.append(u'<tr><td>%s:</td><td>%s</td></tr>' % (bf.label, bf))
|
output.append(u'<tr><td>%s</td><td>%s</td></tr>' % (bf.label_tag(bf.verbose_name+':'), bf))
|
||||||
return u'\n'.join(output)
|
return u'\n'.join(output)
|
||||||
|
|
||||||
def as_ul(self):
|
def as_ul(self):
|
||||||
|
@ -95,7 +96,7 @@ class Form(object):
|
||||||
line = u'<li>'
|
line = u'<li>'
|
||||||
if bf.errors:
|
if bf.errors:
|
||||||
line += str(bf.errors)
|
line += str(bf.errors)
|
||||||
line += u'%s: %s</li>' % (bf.label, bf)
|
line += u'%s %s</li>' % (bf.label_tag(bf.verbose_name+':'), bf)
|
||||||
output.append(line)
|
output.append(line)
|
||||||
return u'\n'.join(output)
|
return u'\n'.join(output)
|
||||||
|
|
||||||
|
@ -190,9 +191,21 @@ class BoundField(object):
|
||||||
"Returns a string of HTML for representing this as a <textarea>."
|
"Returns a string of HTML for representing this as a <textarea>."
|
||||||
return self.as_widget(Textarea(), attrs)
|
return self.as_widget(Textarea(), attrs)
|
||||||
|
|
||||||
def _label(self):
|
def _verbose_name(self):
|
||||||
return pretty_name(self._name)
|
return pretty_name(self._name)
|
||||||
label = property(_label)
|
verbose_name = property(_verbose_name)
|
||||||
|
|
||||||
|
def label_tag(self, contents=None):
|
||||||
|
"""
|
||||||
|
Wraps the given contents in a <label>, if the field has an ID attribute.
|
||||||
|
Does not HTML-escape the contents. If contents aren't given, uses the
|
||||||
|
field's HTML-escaped verbose_name.
|
||||||
|
"""
|
||||||
|
contents = contents or escape(self.verbose_name)
|
||||||
|
id_ = self._field.widget.attrs.get('id') or self.auto_id
|
||||||
|
if id_:
|
||||||
|
contents = '<label for="%s">%s</label>' % (id_, contents)
|
||||||
|
return contents
|
||||||
|
|
||||||
def _auto_id(self):
|
def _auto_id(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1251,20 +1251,25 @@ u'* This field is required.'
|
||||||
|
|
||||||
"auto_id" tells the Form to add an "id" attribute to each form element.
|
"auto_id" tells the Form to add an "id" attribute to each form element.
|
||||||
If it's a string that contains '%s', Django will use that as a format string
|
If it's a string that contains '%s', Django will use that as a format string
|
||||||
into which the field's name will be inserted.
|
into which the field's name will be inserted. It will also put a <label> around
|
||||||
|
the human-readable labels for a field.
|
||||||
>>> p = Person(auto_id='id_%s')
|
>>> p = Person(auto_id='id_%s')
|
||||||
>>> print p.as_ul()
|
>>> print p.as_ul()
|
||||||
<li>First name: <input type="text" name="first_name" id="id_first_name" /></li>
|
<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
|
||||||
<li>Last name: <input type="text" name="last_name" id="id_last_name" /></li>
|
<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
|
||||||
<li>Birthday: <input type="text" name="birthday" id="id_birthday" /></li>
|
<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li>
|
||||||
|
>>> print p.as_table()
|
||||||
|
<tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
|
||||||
|
<tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
|
||||||
|
<tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr>
|
||||||
|
|
||||||
If auto_id is any True value whose str() does not contain '%s', the "id"
|
If auto_id is any True value whose str() does not contain '%s', the "id"
|
||||||
attribute will be the name of the field.
|
attribute will be the name of the field.
|
||||||
>>> p = Person(auto_id=True)
|
>>> p = Person(auto_id=True)
|
||||||
>>> print p.as_ul()
|
>>> print p.as_ul()
|
||||||
<li>First name: <input type="text" name="first_name" id="first_name" /></li>
|
<li><label for="first_name">First name:</label> <input type="text" name="first_name" id="first_name" /></li>
|
||||||
<li>Last name: <input type="text" name="last_name" id="last_name" /></li>
|
<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
|
||||||
<li>Birthday: <input type="text" name="birthday" id="birthday" /></li>
|
<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>
|
||||||
|
|
||||||
If auto_id is any False value, an "id" attribute won't be output unless it
|
If auto_id is any False value, an "id" attribute won't be output unless it
|
||||||
was manually entered.
|
was manually entered.
|
||||||
|
@ -1275,14 +1280,14 @@ was manually entered.
|
||||||
<li>Birthday: <input type="text" name="birthday" /></li>
|
<li>Birthday: <input type="text" name="birthday" /></li>
|
||||||
|
|
||||||
In this example, auto_id is False, but the "id" attribute for the "first_name"
|
In this example, auto_id is False, but the "id" attribute for the "first_name"
|
||||||
field is given.
|
field is given. Also note that field gets a <label>, while the others don't.
|
||||||
>>> class PersonNew(Form):
|
>>> class PersonNew(Form):
|
||||||
... first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
|
... first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
|
||||||
... last_name = CharField()
|
... last_name = CharField()
|
||||||
... birthday = DateField()
|
... birthday = DateField()
|
||||||
>>> p = PersonNew(auto_id=False)
|
>>> p = PersonNew(auto_id=False)
|
||||||
>>> print p.as_ul()
|
>>> print p.as_ul()
|
||||||
<li>First name: <input type="text" id="first_name_id" name="first_name" /></li>
|
<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
|
||||||
<li>Last name: <input type="text" name="last_name" /></li>
|
<li>Last name: <input type="text" name="last_name" /></li>
|
||||||
<li>Birthday: <input type="text" name="birthday" /></li>
|
<li>Birthday: <input type="text" name="birthday" /></li>
|
||||||
|
|
||||||
|
@ -1290,9 +1295,9 @@ If the "id" attribute is specified in the Form and auto_id is True, the "id"
|
||||||
attribute in the Form gets precedence.
|
attribute in the Form gets precedence.
|
||||||
>>> p = PersonNew(auto_id=True)
|
>>> p = PersonNew(auto_id=True)
|
||||||
>>> print p.as_ul()
|
>>> print p.as_ul()
|
||||||
<li>First name: <input type="text" id="first_name_id" name="first_name" /></li>
|
<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
|
||||||
<li>Last name: <input type="text" name="last_name" id="last_name" /></li>
|
<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
|
||||||
<li>Birthday: <input type="text" name="birthday" id="birthday" /></li>
|
<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>
|
||||||
|
|
||||||
>>> class SignupForm(Form):
|
>>> class SignupForm(Form):
|
||||||
... email = EmailField()
|
... email = EmailField()
|
||||||
|
@ -1606,10 +1611,57 @@ particular field.
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
Use form.[field].verbose_name to output a field's "verbose name" -- its field
|
||||||
|
name with underscores converted to spaces, and the initial letter capitalized.
|
||||||
|
>>> t = Template('''<form action="">
|
||||||
|
... <p><label>{{ form.username.verbose_name }}: {{ form.username }}</label></p>
|
||||||
|
... <p><label>{{ form.password1.verbose_name }}: {{ form.password1 }}</label></p>
|
||||||
|
... <p><label>{{ form.password2.verbose_name }}: {{ form.password2 }}</label></p>
|
||||||
|
... <input type="submit" />
|
||||||
|
... </form>''')
|
||||||
|
>>> print t.render(Context({'form': UserRegistration()}))
|
||||||
|
<form action="">
|
||||||
|
<p><label>Username: <input type="text" name="username" /></label></p>
|
||||||
|
<p><label>Password1: <input type="password" name="password1" /></label></p>
|
||||||
|
<p><label>Password2: <input type="password" name="password2" /></label></p>
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
User form.[field].label_tag to output a field's verbose_name with a <label>
|
||||||
|
tag wrapped around it, but *only* if the given field has an "id" attribute.
|
||||||
|
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>
|
||||||
|
... <input type="submit" />
|
||||||
|
... </form>''')
|
||||||
|
>>> print t.render(Context({'form': UserRegistration()}))
|
||||||
|
<form action="">
|
||||||
|
<p>Username: <input type="text" name="username" /></p>
|
||||||
|
<p>Password1: <input type="password" name="password1" /></p>
|
||||||
|
<p>Password2: <input type="password" name="password2" /></p>
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
|
||||||
|
<form action="">
|
||||||
|
<p><label for="id_username">Username</label>: <input type="text" name="username" id="id_username" /></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>
|
||||||
|
|
||||||
To display the errors that aren't associated with a particular field -- e.g.,
|
To display the errors that aren't associated with a particular field -- e.g.,
|
||||||
the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
|
the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
|
||||||
template. If used on its own, it is displayed as a <ul> (or an empty string, if
|
template. If used on its own, it is displayed as a <ul> (or an empty string, if
|
||||||
the list of errors is empty). You can also use it in {% if %} statements.
|
the list of errors is empty). You can also use it in {% if %} statements.
|
||||||
|
>>> t = Template('''<form action="">
|
||||||
|
... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
|
||||||
|
... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
|
||||||
|
... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
|
||||||
|
... <input type="submit" />
|
||||||
|
... </form>''')
|
||||||
>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
|
>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
|
||||||
<form action="">
|
<form action="">
|
||||||
<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
|
<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
|
||||||
|
|
Loading…
Reference in New Issue