newforms: Added Field.widget_attrs() hook, which lets a Field designate HTML attributes to use in its widget. Implemented CharField.widget_attrs(), which sets the HTML maxlength attribute for <input type='text'> and <input type='password'>. Thanks for the idea, Gary Doades
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4187 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4e72dc86ff
commit
f10a910577
|
@ -4,7 +4,7 @@ Field classes
|
||||||
|
|
||||||
from django.utils.translation import gettext
|
from django.utils.translation import gettext
|
||||||
from util import ValidationError, smart_unicode
|
from util import ValidationError, smart_unicode
|
||||||
from widgets import TextInput, CheckboxInput, Select, SelectMultiple
|
from widgets import TextInput, PasswordInput, CheckboxInput, Select, SelectMultiple
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
@ -37,6 +37,12 @@ class Field(object):
|
||||||
widget = widget or self.widget
|
widget = widget or self.widget
|
||||||
if isinstance(widget, type):
|
if isinstance(widget, type):
|
||||||
widget = widget()
|
widget = widget()
|
||||||
|
|
||||||
|
# Hook into self.widget_attrs() for any Field-specific HTML attributes.
|
||||||
|
extra_attrs = self.widget_attrs(widget)
|
||||||
|
if extra_attrs:
|
||||||
|
widget.attrs.update(extra_attrs)
|
||||||
|
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
|
|
||||||
# Increase the creation counter, and save our local copy.
|
# Increase the creation counter, and save our local copy.
|
||||||
|
@ -54,10 +60,18 @@ class Field(object):
|
||||||
raise ValidationError(gettext(u'This field is required.'))
|
raise ValidationError(gettext(u'This field is required.'))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def widget_attrs(self, widget):
|
||||||
|
"""
|
||||||
|
Given a Widget instance (*not* a Widget class), returns a dictionary of
|
||||||
|
any HTML attributes that should be added to the Widget, based on this
|
||||||
|
Field.
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
class CharField(Field):
|
class CharField(Field):
|
||||||
def __init__(self, max_length=None, min_length=None, required=True, widget=None):
|
def __init__(self, max_length=None, min_length=None, required=True, widget=None):
|
||||||
Field.__init__(self, required, widget)
|
|
||||||
self.max_length, self.min_length = max_length, min_length
|
self.max_length, self.min_length = max_length, min_length
|
||||||
|
Field.__init__(self, required, widget)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"Validates max_length and min_length. Returns a Unicode object."
|
"Validates max_length and min_length. Returns a Unicode object."
|
||||||
|
@ -70,6 +84,10 @@ class CharField(Field):
|
||||||
raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
|
raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def widget_attrs(self, widget):
|
||||||
|
if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
|
||||||
|
return {'maxlength': str(self.max_length)}
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1736,7 +1736,7 @@ Form.clean() is required to return a dictionary of all clean data.
|
||||||
>>> f = UserRegistration({})
|
>>> f = UserRegistration({})
|
||||||
>>> print f.as_table()
|
>>> print f.as_table()
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
||||||
<tr><td>Username:</td><td><input type="text" name="username" /></td></tr>
|
<tr><td>Username:</td><td><input type="text" name="username" maxlength="10" /></td></tr>
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
||||||
<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr>
|
<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr>
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
|
||||||
|
@ -1748,12 +1748,12 @@ Form.clean() is required to return a dictionary of all clean data.
|
||||||
{'__all__': [u'Please make sure your passwords match.']}
|
{'__all__': [u'Please make sure your passwords match.']}
|
||||||
>>> print f.as_table()
|
>>> print f.as_table()
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
|
||||||
<tr><td>Username:</td><td><input type="text" name="username" value="adrian" /></td></tr>
|
<tr><td>Username:</td><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>
|
||||||
<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>
|
<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>
|
||||||
<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>
|
<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>
|
||||||
>>> print f.as_ul()
|
>>> print f.as_ul()
|
||||||
<li><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></li>
|
<li><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></li>
|
||||||
<li>Username: <input type="text" name="username" value="adrian" /></li>
|
<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li>
|
||||||
<li>Password1: <input type="password" name="password1" value="foo" /></li>
|
<li>Password1: <input type="password" name="password1" value="foo" /></li>
|
||||||
<li>Password2: <input type="password" name="password2" value="bar" /></li>
|
<li>Password2: <input type="password" name="password2" value="bar" /></li>
|
||||||
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'})
|
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'})
|
||||||
|
@ -1881,6 +1881,33 @@ A Form's fields are displayed in the same order in which they were defined.
|
||||||
<tr><td>Field13:</td><td><input type="text" name="field13" /></td></tr>
|
<tr><td>Field13:</td><td><input type="text" name="field13" /></td></tr>
|
||||||
<tr><td>Field14:</td><td><input type="text" name="field14" /></td></tr>
|
<tr><td>Field14:</td><td><input type="text" name="field14" /></td></tr>
|
||||||
|
|
||||||
|
Some Field classes have an effect on the HTML attributes of their associated
|
||||||
|
Widget. If you set max_length in a CharField and its associated widget is
|
||||||
|
either a TextInput or PasswordInput, then the widget's rendered HTML will
|
||||||
|
include the "maxlength" attribute.
|
||||||
|
>>> class UserRegistration(Form):
|
||||||
|
... username = CharField(max_length=10) # uses TextInput by default
|
||||||
|
... password = CharField(max_length=10, widget=PasswordInput)
|
||||||
|
... realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test
|
||||||
|
... address = CharField() # no max_length defined here
|
||||||
|
>>> p = UserRegistration()
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" maxlength="10" /></li>
|
||||||
|
<li>Password: <input type="password" name="password" maxlength="10" /></li>
|
||||||
|
<li>Realname: <input type="text" name="realname" maxlength="10" /></li>
|
||||||
|
<li>Address: <input type="text" name="address" /></li>
|
||||||
|
|
||||||
|
If you specify a custom "attrs" that includes the "maxlength" attribute,
|
||||||
|
the Field's max_length attribute will override whatever "maxlength" you specify
|
||||||
|
in "attrs".
|
||||||
|
>>> class UserRegistration(Form):
|
||||||
|
... username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20}))
|
||||||
|
... password = CharField(max_length=10, widget=PasswordInput)
|
||||||
|
>>> p = UserRegistration()
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" maxlength="10" /></li>
|
||||||
|
<li>Password: <input type="password" name="password" maxlength="10" /></li>
|
||||||
|
|
||||||
# Basic form processing in a view #############################################
|
# Basic form processing in a view #############################################
|
||||||
|
|
||||||
>>> from django.template import Template, Context
|
>>> from django.template import Template, Context
|
||||||
|
@ -1906,7 +1933,7 @@ Case 1: GET (an empty form, with no errors).
|
||||||
>>> print my_function('GET', {})
|
>>> print my_function('GET', {})
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
<table>
|
<table>
|
||||||
<tr><td>Username:</td><td><input type="text" name="username" /></td></tr>
|
<tr><td>Username:</td><td><input type="text" name="username" maxlength="10" /></td></tr>
|
||||||
<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr>
|
<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr>
|
||||||
<tr><td>Password2:</td><td><input type="password" name="password2" /></td></tr>
|
<tr><td>Password2:</td><td><input type="password" name="password2" /></td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1919,7 +1946,7 @@ Case 2: POST with erroneous data (a redisplayed form, with errors).
|
||||||
<table>
|
<table>
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
|
||||||
<tr><td colspan="2"><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul></td></tr>
|
<tr><td colspan="2"><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul></td></tr>
|
||||||
<tr><td>Username:</td><td><input type="text" name="username" value="this-is-a-long-username" /></td></tr>
|
<tr><td>Username:</td><td><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
|
||||||
<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>
|
<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>
|
||||||
<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>
|
<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1954,14 +1981,14 @@ particular field.
|
||||||
... </form>''')
|
... </form>''')
|
||||||
>>> print t.render(Context({'form': UserRegistration()}))
|
>>> print t.render(Context({'form': UserRegistration()}))
|
||||||
<form action="">
|
<form action="">
|
||||||
<p><label>Your username: <input type="text" name="username" /></label></p>
|
<p><label>Your username: <input type="text" name="username" maxlength="10" /></label></p>
|
||||||
<p><label>Password: <input type="password" name="password1" /></label></p>
|
<p><label>Password: <input type="password" name="password1" /></label></p>
|
||||||
<p><label>Password (again): <input type="password" name="password2" /></label></p>
|
<p><label>Password (again): <input type="password" name="password2" /></label></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
</form>
|
</form>
|
||||||
>>> print t.render(Context({'form': UserRegistration({'username': 'django'})}))
|
>>> print t.render(Context({'form': UserRegistration({'username': 'django'})}))
|
||||||
<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" maxlength="10" /></label></p>
|
||||||
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p>
|
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p>
|
||||||
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p>
|
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
|
@ -1977,7 +2004,7 @@ name with underscores converted to spaces, and the initial letter capitalized.
|
||||||
... </form>''')
|
... </form>''')
|
||||||
>>> print t.render(Context({'form': UserRegistration()}))
|
>>> print t.render(Context({'form': UserRegistration()}))
|
||||||
<form action="">
|
<form action="">
|
||||||
<p><label>Username: <input type="text" name="username" /></label></p>
|
<p><label>Username: <input type="text" name="username" maxlength="10" /></label></p>
|
||||||
<p><label>Password1: <input type="password" name="password1" /></label></p>
|
<p><label>Password1: <input type="password" name="password1" /></label></p>
|
||||||
<p><label>Password2: <input type="password" name="password2" /></label></p>
|
<p><label>Password2: <input type="password" name="password2" /></label></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
|
@ -1995,14 +2022,14 @@ field an "id" attribute.
|
||||||
... </form>''')
|
... </form>''')
|
||||||
>>> print t.render(Context({'form': UserRegistration()}))
|
>>> print t.render(Context({'form': UserRegistration()}))
|
||||||
<form action="">
|
<form action="">
|
||||||
<p>Username: <input type="text" name="username" /></p>
|
<p>Username: <input type="text" name="username" maxlength="10" /></p>
|
||||||
<p>Password1: <input type="password" name="password1" /></p>
|
<p>Password1: <input type="password" name="password1" /></p>
|
||||||
<p>Password2: <input type="password" name="password2" /></p>
|
<p>Password2: <input type="password" name="password2" /></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
</form>
|
</form>
|
||||||
>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
|
>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
|
||||||
<form action="">
|
<form action="">
|
||||||
<p><label for="id_username">Username</label>: <input type="text" name="username" id="id_username" /></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_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_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
|
@ -2020,7 +2047,7 @@ the list of errors is empty). You can also use it in {% if %} statements.
|
||||||
... </form>''')
|
... </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" maxlength="10" /></label></p>
|
||||||
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
|
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
|
||||||
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
|
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
|
@ -2035,7 +2062,7 @@ the list of errors is empty). You can also use it in {% if %} statements.
|
||||||
>>> 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="">
|
||||||
<ul class="errorlist"><li>Please make sure your passwords match.</li></ul>
|
<ul class="errorlist"><li>Please make sure your passwords match.</li></ul>
|
||||||
<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
|
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p>
|
||||||
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
|
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
|
||||||
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
|
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
|
|
Loading…
Reference in New Issue