Navigation Menu

Skip to content

Commit

Permalink
[soc2009/model-validation] validators refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
honzakral committed Aug 15, 2009
1 parent 05524ab commit 9578491
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 83 deletions.
118 changes: 45 additions & 73 deletions django/core/validators.py
Expand Up @@ -14,14 +14,6 @@
# It's OK if Django settings aren't configured.
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):
regex = ''
message = _(u'Enter a valid value.')
Expand All @@ -46,7 +38,13 @@ def __call__(self, value):
raise ValidationError(self.message, code=self.code)

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):
super(URLValidator, self).__init__()
Expand All @@ -72,97 +70,70 @@ def __call__(self, value):
except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError(_(u'This URL appears to be a broken link.'), code='invalid_link')


def validate_integer(value):
try:
int(value)
except (ValueError, TypeError), e:
raise ValidationError('')


email_re = re.compile(
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')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain

def validate_email(value):
if not email_re.search(smart_unicode(value)):
raise ValidationError(_(u'Enter a valid e-mail address.'), code='invalid')
validate_email = RegexValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')

slug_re = re.compile(r'^[-\w]+$')

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'
)
validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), '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}$')

def validate_ipv4_address(value):
if not ipv4_re.search(smart_unicode(value)):
raise ValidationError(
_(u'Enter a valid IPv4 address.'),
code="invalid"
)
validate_ipv4_address = RegexValidator(ipv4_re, _(u'Enter a valid IPv4 address.'), 'invalid')

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):
def __init__(self, max_value):
self.max_value = max_value

def __call__(self, value):
if value > self.max_value:
raise ValidationError(
_(u'Ensure this value is less than or equal to %s.') % self.max_value,
code='max_value',
params=(self.max_value,)
)
class BaseValidator(object):
compare = lambda self, a, b: a is b
clean = lambda self, x: x
message = _(u'Ensure this value is %(limit_value)s (it is %(show_value)s).')
code = 'limit_value'

class MinValueValidator(object):
def __init__(self, min_value):
self.min_value = min_value
def __init__(self, limit_value):
self.limit_value = limit_value

def __call__(self, value):
if value < self.min_value:
cleaned = self.clean(value)
if self.compare(cleaned, self.limit_value):
raise ValidationError(
_(u'Ensure this value is greater than or equal to %s.') % self.min_value,
code='min_value',
params=(self.min_value,)
self.message,
code=self.code,
params={'limit_value': self.limit_value, 'show_value': cleaned}
)

class MinLengthValidator(object):
def __init__(self, min_length):
self.min_length = min_length
class MaxValueValidator(BaseValidator):
compare = lambda self, a, b: a > b
message = _(u'Ensure this value is less than or equal to %(limit_value)s.')
code = 'max_value'

def __call__(self, value):
value_len = len(value)
if value_len < self.min_length:
raise ValidationError(
_(u'Ensure this value has at least %(min)d characters (it has %(length)d).'),
code='min_length',
params={ 'min': self.min_length, 'length': value_len}
)
class MinValueValidator(BaseValidator):
compare = lambda self, a, b: a < b
message = _(u'Ensure this value is greater than or equal to %(limit_value)s.')
code = 'min_value'

class MaxLengthValidator(object):
def __init__(self, max_length):
self.max_length = max_length
class MinLengthValidator(BaseValidator):
compare = lambda self, a, b: a < b
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'

class MaxLengthValidator(BaseValidator):
compare = lambda self, a, b: a > b
clean = lambda self, x: len(x)
message = _(u'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
code = '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):
def get_value(self, name, all_values, obj):
Expand All @@ -185,3 +156,4 @@ def __call__(self, value, all_values={}, obj=None):
if self.get_value(self.other_field, all_values, obj) in EMPTY_VALUES:
if value in EMPTY_VALUES:
raise ValidationError('This field is required if %s is blank.' % self.other_field)

8 changes: 4 additions & 4 deletions django/forms/fields.py
Expand Up @@ -204,8 +204,8 @@ def widget_attrs(self, widget):
class IntegerField(Field):
default_error_messages = {
'invalid': _(u'Enter a whole number.'),
'max_value': _(u'Ensure this value is less than or equal to %s.'),
'min_value': _(u'Ensure this value is greater 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 %(limit_value)s.'),
}

def __init__(self, max_value=None, min_value=None, *args, **kwargs):
Expand Down Expand Up @@ -254,8 +254,8 @@ def to_python(self, value):
class DecimalField(Field):
default_error_messages = {
'invalid': _(u'Enter a number.'),
'max_value': _(u'Ensure this value is less than or equal to %s.'),
'min_value': _(u'Ensure this value is greater 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 %(limit_value)s.'),
'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_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
Expand Down
12 changes: 6 additions & 6 deletions tests/regressiontests/forms/error_messages.py
Expand Up @@ -26,8 +26,8 @@
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
Expand All @@ -50,8 +50,8 @@
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = FloatField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
Expand All @@ -74,8 +74,8 @@
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> e['max_digits'] = 'MAX DIGITS IS %s'
>>> e['max_decimal_places'] = 'MAX DP IS %s'
>>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'
Expand Down

0 comments on commit 9578491

Please sign in to comment.