Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added ChoiceField, MultipleChoiceField to django.newforms

git-svn-id: http://code.djangoproject.com/svn/django/trunk@3959 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 6645d1fe48868814e4c73056b68be5c3861ed2d0 1 parent 36786d2
Adrian Holovaty adrianholovaty authored
1  django/newforms/__init__.py
View
@@ -3,7 +3,6 @@
TODO:
Validation not tied to a particular field
- <select> and validation of lists
Default value for field
Field labels
Nestable Forms
56 django/newforms/fields.py
View
@@ -3,7 +3,7 @@
"""
from util import ValidationError, DEFAULT_ENCODING
-from widgets import TextInput, CheckboxInput
+from widgets import TextInput, CheckboxInput, Select, SelectMultiple
import datetime
import re
import time
@@ -13,11 +13,17 @@
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
'RegexField', 'EmailField', 'URLField', 'BooleanField',
+ 'ChoiceField', 'MultipleChoiceField',
)
# These values, if given to to_python(), will trigger the self.required check.
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):
widget = TextInput # Default widget to use when rendering this type of Field.
@@ -205,3 +211,51 @@ def to_python(self, value):
"Returns a Python boolean object."
Field.to_python(self, 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
100 tests/regressiontests/forms/tests.py
View
@@ -680,6 +680,64 @@
>>> f.to_python('Django rocks')
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 ########################################################################
>>> class Person(Form):
@@ -787,6 +845,48 @@
>>> f['message'].as_text()
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__":
Please sign in to comment.
Something went wrong with that request. Please try again.