Added ChoiceField, MultipleChoiceField to django.newforms
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3959 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
36786d28f5
commit
6645d1fe48
|
@ -3,7 +3,6 @@ Django validation and HTML form handling.
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
Validation not tied to a particular field
|
Validation not tied to a particular field
|
||||||
<select> and validation of lists
|
|
||||||
Default value for field
|
Default value for field
|
||||||
Field labels
|
Field labels
|
||||||
Nestable Forms
|
Nestable Forms
|
||||||
|
|
|
@ -3,7 +3,7 @@ Field classes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from util import ValidationError, DEFAULT_ENCODING
|
from util import ValidationError, DEFAULT_ENCODING
|
||||||
from widgets import TextInput, CheckboxInput
|
from widgets import TextInput, CheckboxInput, Select, SelectMultiple
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
@ -13,11 +13,17 @@ __all__ = (
|
||||||
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
||||||
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
||||||
'RegexField', 'EmailField', 'URLField', 'BooleanField',
|
'RegexField', 'EmailField', 'URLField', 'BooleanField',
|
||||||
|
'ChoiceField', 'MultipleChoiceField',
|
||||||
)
|
)
|
||||||
|
|
||||||
# These values, if given to to_python(), will trigger the self.required check.
|
# These values, if given to to_python(), will trigger the self.required check.
|
||||||
EMPTY_VALUES = (None, '')
|
EMPTY_VALUES = (None, '')
|
||||||
|
|
||||||
|
try:
|
||||||
|
set # Only available in Python 2.4+
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # Python 2.3 fallback
|
||||||
|
|
||||||
class Field(object):
|
class Field(object):
|
||||||
widget = TextInput # Default widget to use when rendering this type of Field.
|
widget = TextInput # Default widget to use when rendering this type of Field.
|
||||||
|
|
||||||
|
@ -205,3 +211,51 @@ class BooleanField(Field):
|
||||||
"Returns a Python boolean object."
|
"Returns a Python boolean object."
|
||||||
Field.to_python(self, value)
|
Field.to_python(self, value)
|
||||||
return bool(value)
|
return bool(value)
|
||||||
|
|
||||||
|
class ChoiceField(Field):
|
||||||
|
def __init__(self, choices=(), required=True, widget=Select):
|
||||||
|
if isinstance(widget, type):
|
||||||
|
widget = widget(choices=choices)
|
||||||
|
Field.__init__(self, required, widget)
|
||||||
|
self.choices = choices
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
"""
|
||||||
|
Validates that the input is in self.choices.
|
||||||
|
"""
|
||||||
|
value = Field.to_python(self, value)
|
||||||
|
if value in EMPTY_VALUES: value = u''
|
||||||
|
if not isinstance(value, basestring):
|
||||||
|
value = unicode(str(value), DEFAULT_ENCODING)
|
||||||
|
elif not isinstance(value, unicode):
|
||||||
|
value = unicode(value, DEFAULT_ENCODING)
|
||||||
|
valid_values = set([str(k) for k, v in self.choices])
|
||||||
|
if value not in valid_values:
|
||||||
|
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
class MultipleChoiceField(ChoiceField):
|
||||||
|
def __init__(self, choices=(), required=True, widget=SelectMultiple):
|
||||||
|
ChoiceField.__init__(self, choices, required, widget)
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
"""
|
||||||
|
Validates that the input is a list or tuple.
|
||||||
|
"""
|
||||||
|
if not isinstance(value, (list, tuple)):
|
||||||
|
raise ValidationError(u'Enter a list of values.')
|
||||||
|
if self.required and not value:
|
||||||
|
raise ValidationError(u'This field is required.')
|
||||||
|
new_value = []
|
||||||
|
for val in value:
|
||||||
|
if not isinstance(val, basestring):
|
||||||
|
value = unicode(str(val), DEFAULT_ENCODING)
|
||||||
|
elif not isinstance(val, unicode):
|
||||||
|
value = unicode(val, DEFAULT_ENCODING)
|
||||||
|
new_value.append(value)
|
||||||
|
# Validate that each value in the value list is in self.choices.
|
||||||
|
valid_values = set([k for k, v in self.choices])
|
||||||
|
for val in new_value:
|
||||||
|
if val not in valid_values:
|
||||||
|
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % val)
|
||||||
|
return new_value
|
||||||
|
|
|
@ -680,6 +680,64 @@ False
|
||||||
>>> f.to_python('Django rocks')
|
>>> f.to_python('Django rocks')
|
||||||
True
|
True
|
||||||
|
|
||||||
|
# ChoiceField #################################################################
|
||||||
|
|
||||||
|
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
|
||||||
|
>>> f.to_python(1)
|
||||||
|
u'1'
|
||||||
|
>>> f.to_python('1')
|
||||||
|
u'1'
|
||||||
|
>>> f.to_python(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.to_python('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.to_python('3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
||||||
|
|
||||||
|
>>> f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')])
|
||||||
|
>>> f.to_python('J')
|
||||||
|
u'J'
|
||||||
|
>>> f.to_python('John')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. John is not one of the available choices.']
|
||||||
|
|
||||||
|
# MultipleChoiceField #########################################################
|
||||||
|
|
||||||
|
>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')])
|
||||||
|
>>> f.to_python([1])
|
||||||
|
[u'1']
|
||||||
|
>>> f.to_python(['1'])
|
||||||
|
[u'1']
|
||||||
|
>>> f.to_python(['1', '2'])
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.to_python([1, '2'])
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.to_python((1, '2'))
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.to_python('hello')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a list of values.']
|
||||||
|
>>> f.to_python([])
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.to_python(())
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.to_python(['3'])
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
||||||
|
|
||||||
# Form ########################################################################
|
# Form ########################################################################
|
||||||
|
|
||||||
>>> class Person(Form):
|
>>> class Person(Form):
|
||||||
|
@ -787,6 +845,48 @@ u'<textarea name="subject">Hello</textarea>'
|
||||||
>>> f['message'].as_text()
|
>>> f['message'].as_text()
|
||||||
u'<input type="text" name="message" value="I love you." />'
|
u'<input type="text" name="message" value="I love you." />'
|
||||||
|
|
||||||
|
For a form with a <select>, use ChoiceField:
|
||||||
|
>>> class FrameworkForm(Form):
|
||||||
|
... name = CharField()
|
||||||
|
... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')])
|
||||||
|
>>> f = FrameworkForm()
|
||||||
|
>>> print f['language']
|
||||||
|
<select name="language">
|
||||||
|
<option value="P">Python</option>
|
||||||
|
<option value="J">Java</option>
|
||||||
|
</select>
|
||||||
|
>>> f = FrameworkForm({'name': 'Django', 'language': 'P'})
|
||||||
|
>>> print f['language']
|
||||||
|
<select name="language">
|
||||||
|
<option value="P" selected="selected">Python</option>
|
||||||
|
<option value="J">Java</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
MultipleChoiceField is a special case, as its data is required to be a list:
|
||||||
|
>>> class SongForm(Form):
|
||||||
|
... name = CharField()
|
||||||
|
... composers = MultipleChoiceField()
|
||||||
|
>>> f = SongForm()
|
||||||
|
>>> print f['composers']
|
||||||
|
<select multiple="multiple" name="composers">
|
||||||
|
</select>
|
||||||
|
>>> class SongForm(Form):
|
||||||
|
... name = CharField()
|
||||||
|
... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
|
||||||
|
>>> f = SongForm()
|
||||||
|
>>> print f['composers']
|
||||||
|
<select multiple="multiple" name="composers">
|
||||||
|
<option value="J">John Lennon</option>
|
||||||
|
<option value="P">Paul McCartney</option>
|
||||||
|
</select>
|
||||||
|
>>> f = SongForm({'name': 'Yesterday', 'composers': ['P']})
|
||||||
|
>>> print f['name']
|
||||||
|
<input type="text" name="name" value="Yesterday" />
|
||||||
|
>>> print f['composers']
|
||||||
|
<select multiple="multiple" name="composers">
|
||||||
|
<option value="J">John Lennon</option>
|
||||||
|
<option value="P" selected="selected">Paul McCartney</option>
|
||||||
|
</select>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Reference in New Issue