newforms: Added a bunch of unit tests and fixed some bugs in the case of required=False for various Field subclasses
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4113 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
684cf3c6fe
commit
56ad38a826
|
@ -76,6 +76,8 @@ class IntegerField(Field):
|
||||||
of int().
|
of int().
|
||||||
"""
|
"""
|
||||||
super(IntegerField, self).clean(value)
|
super(IntegerField, self).clean(value)
|
||||||
|
if not self.required and value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
try:
|
try:
|
||||||
return int(value)
|
return int(value)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
|
@ -170,7 +172,9 @@ class RegexField(Field):
|
||||||
Field.clean(self, value)
|
Field.clean(self, value)
|
||||||
if value in EMPTY_VALUES: value = u''
|
if value in EMPTY_VALUES: value = u''
|
||||||
value = smart_unicode(value)
|
value = smart_unicode(value)
|
||||||
if (value or self.required) and not self.regex.search(value):
|
if not self.required and value == u'':
|
||||||
|
return value
|
||||||
|
if not self.regex.search(value):
|
||||||
raise ValidationError(self.error_message)
|
raise ValidationError(self.error_message)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -246,6 +250,8 @@ class ChoiceField(Field):
|
||||||
value = Field.clean(self, value)
|
value = Field.clean(self, value)
|
||||||
if value in EMPTY_VALUES: value = u''
|
if value in EMPTY_VALUES: value = u''
|
||||||
value = smart_unicode(value)
|
value = smart_unicode(value)
|
||||||
|
if not self.required and value == u'':
|
||||||
|
return value
|
||||||
valid_values = set([str(k) for k, v in self.choices])
|
valid_values = set([str(k) for k, v in self.choices])
|
||||||
if value not in valid_values:
|
if value not in valid_values:
|
||||||
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
|
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
|
||||||
|
@ -259,10 +265,12 @@ class MultipleChoiceField(ChoiceField):
|
||||||
"""
|
"""
|
||||||
Validates that the input is a list or tuple.
|
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:
|
if self.required and not value:
|
||||||
raise ValidationError(u'This field is required.')
|
raise ValidationError(u'This field is required.')
|
||||||
|
elif not self.required and not value:
|
||||||
|
return []
|
||||||
|
if not isinstance(value, (list, tuple)):
|
||||||
|
raise ValidationError(u'Enter a list of values.')
|
||||||
new_value = []
|
new_value = []
|
||||||
for val in value:
|
for val in value:
|
||||||
val = smart_unicode(val)
|
val = smart_unicode(val)
|
||||||
|
@ -277,6 +285,11 @@ class MultipleChoiceField(ChoiceField):
|
||||||
class ComboField(Field):
|
class ComboField(Field):
|
||||||
def __init__(self, fields=(), required=True, widget=None):
|
def __init__(self, fields=(), required=True, widget=None):
|
||||||
Field.__init__(self, required, widget)
|
Field.__init__(self, required, widget)
|
||||||
|
# Set 'required' to False on the individual fields, because the
|
||||||
|
# required validation will be handled by ComboField, not by those
|
||||||
|
# individual fields.
|
||||||
|
for f in fields:
|
||||||
|
f.required = False
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
|
|
|
@ -477,6 +477,22 @@ beatle J R Ringo False
|
||||||
|
|
||||||
# CharField ###################################################################
|
# CharField ###################################################################
|
||||||
|
|
||||||
|
>>> f = CharField()
|
||||||
|
>>> f.clean(1)
|
||||||
|
u'1'
|
||||||
|
>>> f.clean('hello')
|
||||||
|
u'hello'
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean([1, 2, 3])
|
||||||
|
u'[1, 2, 3]'
|
||||||
|
|
||||||
>>> f = CharField(required=False)
|
>>> f = CharField(required=False)
|
||||||
>>> f.clean(1)
|
>>> f.clean(1)
|
||||||
u'1'
|
u'1'
|
||||||
|
@ -518,6 +534,40 @@ u'1234567890a'
|
||||||
# IntegerField ################################################################
|
# IntegerField ################################################################
|
||||||
|
|
||||||
>>> f = IntegerField()
|
>>> f = IntegerField()
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('1')
|
||||||
|
1
|
||||||
|
>>> isinstance(f.clean('1'), int)
|
||||||
|
True
|
||||||
|
>>> f.clean('23')
|
||||||
|
23
|
||||||
|
>>> f.clean('a')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a whole number.']
|
||||||
|
>>> f.clean('1 ')
|
||||||
|
1
|
||||||
|
>>> f.clean(' 1')
|
||||||
|
1
|
||||||
|
>>> f.clean(' 1 ')
|
||||||
|
1
|
||||||
|
>>> f.clean('1a')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a whole number.']
|
||||||
|
|
||||||
|
>>> f = IntegerField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
>>> f.clean('1')
|
>>> f.clean('1')
|
||||||
1
|
1
|
||||||
>>> isinstance(f.clean('1'), int)
|
>>> isinstance(f.clean('1'), int)
|
||||||
|
@ -681,6 +731,14 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Enter a valid date/time.']
|
ValidationError: [u'Enter a valid date/time.']
|
||||||
|
|
||||||
|
>>> f = DateTimeField(required=False)
|
||||||
|
>>> f.clean(None)
|
||||||
|
>>> repr(f.clean(None))
|
||||||
|
'None'
|
||||||
|
>>> f.clean('')
|
||||||
|
>>> repr(f.clean(''))
|
||||||
|
'None'
|
||||||
|
|
||||||
# RegexField ##################################################################
|
# RegexField ##################################################################
|
||||||
|
|
||||||
>>> f = RegexField('^\d[A-F]\d$')
|
>>> f = RegexField('^\d[A-F]\d$')
|
||||||
|
@ -752,6 +810,34 @@ ValidationError: [u'Enter a four-digit number.']
|
||||||
# EmailField ##################################################################
|
# EmailField ##################################################################
|
||||||
|
|
||||||
>>> f = EmailField()
|
>>> f = EmailField()
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('person@example.com')
|
||||||
|
u'person@example.com'
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid e-mail address.']
|
||||||
|
>>> f.clean('foo@')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid e-mail address.']
|
||||||
|
>>> f.clean('foo@bar')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid e-mail address.']
|
||||||
|
|
||||||
|
>>> f = EmailField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
>>> f.clean('person@example.com')
|
>>> f.clean('person@example.com')
|
||||||
u'person@example.com'
|
u'person@example.com'
|
||||||
>>> f.clean('foo')
|
>>> f.clean('foo')
|
||||||
|
@ -770,6 +856,48 @@ ValidationError: [u'Enter a valid e-mail address.']
|
||||||
# URLField ##################################################################
|
# URLField ##################################################################
|
||||||
|
|
||||||
>>> f = URLField()
|
>>> f = URLField()
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('http://example.com')
|
||||||
|
u'http://example.com'
|
||||||
|
>>> f.clean('http://www.example.com')
|
||||||
|
u'http://www.example.com'
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
>>> f.clean('example.com')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
>>> f.clean('http://')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
>>> f.clean('http://example')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
>>> f.clean('http://example.')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
>>> f.clean('http://.com')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid URL.']
|
||||||
|
|
||||||
|
>>> f = URLField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
>>> f.clean('http://example.com')
|
>>> f.clean('http://example.com')
|
||||||
u'http://example.com'
|
u'http://example.com'
|
||||||
>>> f.clean('http://www.example.com')
|
>>> f.clean('http://www.example.com')
|
||||||
|
@ -820,6 +948,30 @@ ValidationError: [u'This URL appears to be a broken link.']
|
||||||
# BooleanField ################################################################
|
# BooleanField ################################################################
|
||||||
|
|
||||||
>>> f = BooleanField()
|
>>> f = BooleanField()
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(True)
|
||||||
|
True
|
||||||
|
>>> f.clean(False)
|
||||||
|
False
|
||||||
|
>>> f.clean(1)
|
||||||
|
True
|
||||||
|
>>> f.clean(0)
|
||||||
|
False
|
||||||
|
>>> f.clean('Django rocks')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> f = BooleanField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
False
|
||||||
|
>>> f.clean(None)
|
||||||
|
False
|
||||||
>>> f.clean(True)
|
>>> f.clean(True)
|
||||||
True
|
True
|
||||||
>>> f.clean(False)
|
>>> f.clean(False)
|
||||||
|
@ -834,18 +986,32 @@ True
|
||||||
# ChoiceField #################################################################
|
# ChoiceField #################################################################
|
||||||
|
|
||||||
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
|
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
|
||||||
>>> f.clean(1)
|
|
||||||
u'1'
|
|
||||||
>>> f.clean('1')
|
|
||||||
u'1'
|
|
||||||
>>> f.clean(None)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValidationError: [u'This field is required.']
|
|
||||||
>>> f.clean('')
|
>>> f.clean('')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'This field is required.']
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(1)
|
||||||
|
u'1'
|
||||||
|
>>> f.clean('1')
|
||||||
|
u'1'
|
||||||
|
>>> f.clean('3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
||||||
|
|
||||||
|
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean(1)
|
||||||
|
u'1'
|
||||||
|
>>> f.clean('1')
|
||||||
|
u'1'
|
||||||
>>> f.clean('3')
|
>>> f.clean('3')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
|
@ -862,6 +1028,14 @@ ValidationError: [u'Select a valid choice. John is not one of the available choi
|
||||||
# MultipleChoiceField #########################################################
|
# MultipleChoiceField #########################################################
|
||||||
|
|
||||||
>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')])
|
>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')])
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
>>> f.clean([1])
|
>>> f.clean([1])
|
||||||
[u'1']
|
[u'1']
|
||||||
>>> f.clean(['1'])
|
>>> f.clean(['1'])
|
||||||
|
@ -889,10 +1063,38 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
||||||
|
|
||||||
|
>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
[]
|
||||||
|
>>> f.clean(None)
|
||||||
|
[]
|
||||||
|
>>> f.clean([1])
|
||||||
|
[u'1']
|
||||||
|
>>> f.clean(['1'])
|
||||||
|
[u'1']
|
||||||
|
>>> f.clean(['1', '2'])
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.clean([1, '2'])
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.clean((1, '2'))
|
||||||
|
[u'1', u'2']
|
||||||
|
>>> f.clean('hello')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a list of values.']
|
||||||
|
>>> f.clean([])
|
||||||
|
[]
|
||||||
|
>>> f.clean(())
|
||||||
|
[]
|
||||||
|
>>> f.clean(['3'])
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
|
||||||
|
|
||||||
# ComboField ##################################################################
|
# ComboField ##################################################################
|
||||||
|
|
||||||
ComboField takes a list of fields that should be used to validate a value,
|
ComboField takes a list of fields that should be used to validate a value,
|
||||||
in that order:
|
in that order.
|
||||||
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
|
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
|
||||||
>>> f.clean('test@example.com')
|
>>> f.clean('test@example.com')
|
||||||
u'test@example.com'
|
u'test@example.com'
|
||||||
|
@ -913,6 +1115,22 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'This field is required.']
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False)
|
||||||
|
>>> f.clean('test@example.com')
|
||||||
|
u'test@example.com'
|
||||||
|
>>> f.clean('longemailaddress@example.com')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Ensure this value has at most 20 characters.']
|
||||||
|
>>> f.clean('not an e-mail')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid e-mail address.']
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
|
||||||
# Form ########################################################################
|
# Form ########################################################################
|
||||||
|
|
||||||
>>> class Person(Form):
|
>>> class Person(Form):
|
||||||
|
|
Loading…
Reference in New Issue