mirror of https://github.com/django/django.git
Fixed #4807 -- Fixed a couple of corner cases in decimal form input validation.
Based on a suggestion from Chriss Moffit. git-svn-id: http://code.djangoproject.com/svn/django/trunk@5680 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
54a71805aa
commit
92f54aff7a
|
@ -14,6 +14,10 @@ from django.utils.translation import ugettext as _, ugettext_lazy, ungettext
|
||||||
from django.utils.functional import Promise, lazy
|
from django.utils.functional import Promise, lazy
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
import re
|
import re
|
||||||
|
try:
|
||||||
|
from decimal import Decimal, DecimalException
|
||||||
|
except ImportError:
|
||||||
|
from django.utils._decimal import Decimal, DecimalException # Python 2.3
|
||||||
|
|
||||||
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
|
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
|
||||||
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
|
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
|
||||||
|
@ -26,7 +30,6 @@ 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-Z]{2,6}$', re.IGNORECASE) # domain
|
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
|
||||||
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
|
|
||||||
integer_re = re.compile(r'^-?\d+$')
|
integer_re = re.compile(r'^-?\d+$')
|
||||||
ip4_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}$')
|
ip4_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}$')
|
||||||
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
|
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
|
||||||
|
@ -415,12 +418,14 @@ class IsValidDecimal(object):
|
||||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
|
|
||||||
def __call__(self, field_data, all_data):
|
def __call__(self, field_data, all_data):
|
||||||
match = decimal_re.search(str(field_data))
|
try:
|
||||||
if not match:
|
val = Decimal(field_data)
|
||||||
|
except DecimalException:
|
||||||
raise ValidationError, _("Please enter a valid decimal number.")
|
raise ValidationError, _("Please enter a valid decimal number.")
|
||||||
|
|
||||||
digits = len(match.group('digits') or '')
|
pieces = str(val).split('.')
|
||||||
decimals = len(match.group('decimals') or '')
|
decimals = (len(pieces) == 2) and len(pieces[1]) or 0
|
||||||
|
digits = len(pieces[0])
|
||||||
|
|
||||||
if digits + decimals > self.max_digits:
|
if digits + decimals > self.max_digits:
|
||||||
raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
|
raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
|
||||||
|
|
|
@ -12,6 +12,11 @@ from django.utils.encoding import smart_unicode
|
||||||
from util import ErrorList, ValidationError
|
from util import ErrorList, ValidationError
|
||||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
|
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
|
||||||
|
|
||||||
|
try:
|
||||||
|
from decimal import Decimal, DecimalException
|
||||||
|
except ImportError:
|
||||||
|
from django.utils._decimal import Decimal, DecimalException
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Field', 'CharField', 'IntegerField',
|
'Field', 'CharField', 'IntegerField',
|
||||||
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
||||||
|
@ -162,8 +167,6 @@ class FloatField(Field):
|
||||||
raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
|
raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
|
|
||||||
|
|
||||||
class DecimalField(Field):
|
class DecimalField(Field):
|
||||||
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
|
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
|
||||||
self.max_value, self.min_value = max_value, min_value
|
self.max_value, self.min_value = max_value, min_value
|
||||||
|
@ -181,13 +184,13 @@ class DecimalField(Field):
|
||||||
if not self.required and value in EMPTY_VALUES:
|
if not self.required and value in EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
match = decimal_re.search(value)
|
try:
|
||||||
if not match:
|
|
||||||
raise ValidationError(ugettext('Enter a number.'))
|
|
||||||
else:
|
|
||||||
value = Decimal(value)
|
value = Decimal(value)
|
||||||
digits = len(match.group('digits') or '')
|
except DecimalException:
|
||||||
decimals = len(match.group('decimals') or '')
|
raise ValidationError(ugettext('Enter a number.'))
|
||||||
|
pieces = str(value).split('.')
|
||||||
|
decimals = (len(pieces) == 2) and len(pieces[1]) or 0
|
||||||
|
digits = len(pieces[0])
|
||||||
if self.max_value is not None and value > self.max_value:
|
if self.max_value is not None and value > self.max_value:
|
||||||
raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
|
raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
|
||||||
if self.min_value is not None and value < self.min_value:
|
if self.min_value is not None and value < self.min_value:
|
||||||
|
|
|
@ -1176,6 +1176,10 @@ ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
|
||||||
Decimal("1.5")
|
Decimal("1.5")
|
||||||
>>> f.clean('0.5')
|
>>> f.clean('0.5')
|
||||||
Decimal("0.5")
|
Decimal("0.5")
|
||||||
|
>>> f.clean('.5')
|
||||||
|
Decimal("0.5")
|
||||||
|
>>> f.clean('00.50')
|
||||||
|
Decimal("0.50")
|
||||||
|
|
||||||
# DateField ###################################################################
|
# DateField ###################################################################
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue