diff --git a/django/forms/fields.py b/django/forms/fields.py index f3e5528f23..06feb65f30 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -244,18 +244,28 @@ class DecimalField(Field): value = Decimal(value) except DecimalException: raise ValidationError(self.error_messages['invalid']) - pieces = str(value).lstrip("-").split('.') - decimals = (len(pieces) == 2) and len(pieces[1]) or 0 - digits = len(pieces[0]) + + sign, digittuple, exponent = value.as_tuple() + decimals = abs(exponent) + # digittuple doesn't include any leading zeros. + digits = len(digittuple) + if decimals >= digits: + # We have leading zeros up to or past the decimal point. Count + # everything past the decimal point as a digit. We also add one + # for leading zeros before the decimal point (any number of leading + # whole zeros collapse to one digit). + digits = decimals + 1 + whole_digits = digits - decimals + if self.max_value is not None and value > self.max_value: raise ValidationError(self.error_messages['max_value'] % self.max_value) if self.min_value is not None and value < self.min_value: raise ValidationError(self.error_messages['min_value'] % self.min_value) - if self.max_digits is not None and (digits + decimals) > self.max_digits: + if self.max_digits is not None and digits > self.max_digits: raise ValidationError(self.error_messages['max_digits'] % self.max_digits) if self.decimal_places is not None and decimals > self.decimal_places: raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) - if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): + if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places): raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) return value diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index a9aae4f442..ab7968f4a4 100644 --- a/tests/regressiontests/forms/fields.py +++ b/tests/regressiontests/forms/fields.py @@ -403,6 +403,33 @@ True >>> f.clean('00.50') == Decimal("0.50") True + +>>> f = DecimalField(decimal_places=2) +>>> f.clean('0.00000001') +Traceback (most recent call last): +... +ValidationError: [u'Ensure that there are no more than 2 decimal places.'] + + +>>> f = DecimalField(max_digits=3) + +# Leading whole zeros "collapse" to one digit. +>>> f.clean('0000000.10') == Decimal("0.1") +True +>>> f.clean('0000000.100') +Traceback (most recent call last): +... +ValidationError: [u'Ensure that there are no more than 3 digits in total.'] + +# Only leading whole zeros "collapse" to one digit. +>>> f.clean('000000.02') == Decimal('0.02') +True +>>> f.clean('000000.002') +Traceback (most recent call last): +... +ValidationError: [u'Ensure that there are no more than 3 digits in total.'] + + # DateField ################################################################### >>> import datetime