1
0
mirror of https://github.com/django/django.git synced 2025-07-06 18:59:13 +00:00

[soc2009/model-validation] validators refactoring

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@11457 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Honza Král 2009-08-15 13:34:42 +00:00
parent 05524abf1b
commit 9578491379
3 changed files with 55 additions and 83 deletions

View File

@ -14,14 +14,6 @@ except ImportError:
# It's OK if Django settings aren't configured. # It's OK if Django settings aren't configured.
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
url_re = re.compile(
r'^https?://' # http:// or https://
r'(?:(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}|' #domain...
r'localhost|' #localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
r'(?:/?|/\S+)$', re.IGNORECASE)
class RegexValidator(object): class RegexValidator(object):
regex = '' regex = ''
message = _(u'Enter a valid value.') message = _(u'Enter a valid value.')
@ -46,7 +38,13 @@ class RegexValidator(object):
raise ValidationError(self.message, code=self.code) raise ValidationError(self.message, code=self.code)
class URLValidator(RegexValidator): class URLValidator(RegexValidator):
regex = url_re regex = re.compile(
r'^https?://' # http:// or https://
r'(?:(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}|' #domain...
r'localhost|' #localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
r'(?:/?|/\S+)$', re.IGNORECASE)
def __init__(self, verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT): def __init__(self, verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT):
super(URLValidator, self).__init__() super(URLValidator, self).__init__()
@ -72,97 +70,70 @@ class URLValidator(RegexValidator):
except: # urllib2.URLError, httplib.InvalidURL, etc. except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError(_(u'This URL appears to be a broken link.'), code='invalid_link') raise ValidationError(_(u'This URL appears to be a broken link.'), code='invalid_link')
def validate_integer(value): def validate_integer(value):
try: try:
int(value) int(value)
except (ValueError, TypeError), e: except (ValueError, TypeError), e:
raise ValidationError('') raise ValidationError('')
email_re = re.compile( email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
validate_email = RegexValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
def validate_email(value):
if not email_re.search(smart_unicode(value)):
raise ValidationError(_(u'Enter a valid e-mail address.'), code='invalid')
slug_re = re.compile(r'^[-\w]+$') slug_re = re.compile(r'^[-\w]+$')
validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
def validate_slug(value):
if not slug_re.search(smart_unicode(value)):
raise ValidationError(
_(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."),
code='invalid'
)
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
validate_ipv4_address = RegexValidator(ipv4_re, _(u'Enter a valid IPv4 address.'), 'invalid')
def validate_ipv4_address(value):
if not ipv4_re.search(smart_unicode(value)):
raise ValidationError(
_(u'Enter a valid IPv4 address.'),
code="invalid"
)
comma_separated_int_list_re = re.compile('^[\d,]+$') comma_separated_int_list_re = re.compile('^[\d,]+$')
validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _(u'Enter only digits separated by commas.'), 'invalid')
def validate_comma_separated_integer_list(value):
if not comma_separated_int_list_re.search(smart_unicode(value)):
raise ValidationError(
_(u'Enter only digits separated by commas.'),
code="invalid"
)
class MaxValueValidator(object): class BaseValidator(object):
def __init__(self, max_value): compare = lambda self, a, b: a is b
self.max_value = max_value clean = lambda self, x: x
message = _(u'Ensure this value is %(limit_value)s (it is %(show_value)s).')
code = 'limit_value'
def __init__(self, limit_value):
self.limit_value = limit_value
def __call__(self, value): def __call__(self, value):
if value > self.max_value: cleaned = self.clean(value)
if self.compare(cleaned, self.limit_value):
raise ValidationError( raise ValidationError(
_(u'Ensure this value is less than or equal to %s.') % self.max_value, self.message,
code='max_value', code=self.code,
params=(self.max_value,) params={'limit_value': self.limit_value, 'show_value': cleaned}
) )
class MinValueValidator(object): class MaxValueValidator(BaseValidator):
def __init__(self, min_value): compare = lambda self, a, b: a > b
self.min_value = min_value message = _(u'Ensure this value is less than or equal to %(limit_value)s.')
code = 'max_value'
def __call__(self, value): class MinValueValidator(BaseValidator):
if value < self.min_value: compare = lambda self, a, b: a < b
raise ValidationError( message = _(u'Ensure this value is greater than or equal to %(limit_value)s.')
_(u'Ensure this value is greater than or equal to %s.') % self.min_value, code = 'min_value'
code='min_value',
params=(self.min_value,)
)
class MinLengthValidator(object): class MinLengthValidator(BaseValidator):
def __init__(self, min_length): compare = lambda self, a, b: a < b
self.min_length = min_length clean = lambda self, x: len(x)
message = _(u'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).')
code = 'min_length'
def __call__(self, value): class MaxLengthValidator(BaseValidator):
value_len = len(value) compare = lambda self, a, b: a > b
if value_len < self.min_length: clean = lambda self, x: len(x)
raise ValidationError( message = _(u'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
_(u'Ensure this value has at least %(min)d characters (it has %(length)d).'), code = 'max_length'
code='min_length',
params={ 'min': self.min_length, 'length': value_len}
)
class MaxLengthValidator(object):
def __init__(self, max_length):
self.max_length = max_length
def __call__(self, value):
value_len = len(value)
if value_len > self.max_length:
raise ValidationError(
_(u'Ensure this value has at most %(max)d characters (it has %(length)d).'),
code='max_length',
params={ 'max': self.max_length, 'length': value_len}
)
class ComplexValidator(object): class ComplexValidator(object):
def get_value(self, name, all_values, obj): def get_value(self, name, all_values, obj):
@ -185,3 +156,4 @@ class RequiredIfOtherFieldBlank(ComplexValidator):
if self.get_value(self.other_field, all_values, obj) in EMPTY_VALUES: if self.get_value(self.other_field, all_values, obj) in EMPTY_VALUES:
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
raise ValidationError('This field is required if %s is blank.' % self.other_field) raise ValidationError('This field is required if %s is blank.' % self.other_field)

View File

@ -204,8 +204,8 @@ class CharField(Field):
class IntegerField(Field): class IntegerField(Field):
default_error_messages = { default_error_messages = {
'invalid': _(u'Enter a whole number.'), 'invalid': _(u'Enter a whole number.'),
'max_value': _(u'Ensure this value is less than or equal to %s.'), 'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'),
'min_value': _(u'Ensure this value is greater than or equal to %s.'), 'min_value': _(u'Ensure this value is greater than or equal to %(limit_value)s.'),
} }
def __init__(self, max_value=None, min_value=None, *args, **kwargs): def __init__(self, max_value=None, min_value=None, *args, **kwargs):
@ -254,8 +254,8 @@ class FloatField(IntegerField):
class DecimalField(Field): class DecimalField(Field):
default_error_messages = { default_error_messages = {
'invalid': _(u'Enter a number.'), 'invalid': _(u'Enter a number.'),
'max_value': _(u'Ensure this value is less than or equal to %s.'), 'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'),
'min_value': _(u'Ensure this value is greater than or equal to %s.'), 'min_value': _(u'Ensure this value is greater than or equal to %(limit_value)s.'),
'max_digits': _('Ensure that there are no more than %s digits in total.'), 'max_digits': _('Ensure that there are no more than %s digits in total.'),
'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')

View File

@ -26,8 +26,8 @@ ValidationError: [u'LENGTH 11, MAX LENGTH 10']
>>> e = {'required': 'REQUIRED'} >>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID' >>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s' >>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %s' >>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = IntegerField(min_value=5, max_value=10, error_messages=e) >>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('') >>> f.clean('')
Traceback (most recent call last): Traceback (most recent call last):
@ -50,8 +50,8 @@ ValidationError: [u'MAX VALUE IS 10']
>>> e = {'required': 'REQUIRED'} >>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID' >>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s' >>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %s' >>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = FloatField(min_value=5, max_value=10, error_messages=e) >>> f = FloatField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('') >>> f.clean('')
Traceback (most recent call last): Traceback (most recent call last):
@ -74,8 +74,8 @@ ValidationError: [u'MAX VALUE IS 10']
>>> e = {'required': 'REQUIRED'} >>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID' >>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s' >>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %s' >>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> e['max_digits'] = 'MAX DIGITS IS %s' >>> e['max_digits'] = 'MAX DIGITS IS %s'
>>> e['max_decimal_places'] = 'MAX DP IS %s' >>> e['max_decimal_places'] = 'MAX DP IS %s'
>>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s' >>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'