Refactored DecimalField to allow easier subclassing

This commit is contained in:
Ion Scerbatiuc 2015-03-14 07:16:17 -07:00
parent b41808b79a
commit 022c4d540b

View File

@ -757,10 +757,8 @@ class DecimalField(Field):
def to_internal_value(self, data): def to_internal_value(self, data):
""" """
Validates that the input is a decimal number. Returns a Decimal Validate that the input is a decimal number and return a Decimal
instance. Returns None for empty values. Ensures that there are no more instance.
than max_digits in the number, and no more than decimal_places digits
after the decimal point.
""" """
data = smart_text(data).strip() data = smart_text(data).strip()
if len(data) > self.MAX_STRING_LENGTH: if len(data) > self.MAX_STRING_LENGTH:
@ -780,6 +778,16 @@ class DecimalField(Field):
if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')): if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')):
self.fail('invalid') self.fail('invalid')
return self.validate_precision(value)
def validate_precision(self, value):
"""
Ensure that there are no more than max_digits in the number, and no
more than decimal_places digits after the decimal point.
Override this method to disable the precision validation for input
values or to enhance it in any way you need to.
"""
sign, digittuple, exponent = value.as_tuple() sign, digittuple, exponent = value.as_tuple()
decimals = abs(exponent) decimals = abs(exponent)
# digittuple doesn't include any leading zeros. # digittuple doesn't include any leading zeros.
@ -805,16 +813,22 @@ class DecimalField(Field):
if not isinstance(value, decimal.Decimal): if not isinstance(value, decimal.Decimal):
value = decimal.Decimal(six.text_type(value).strip()) value = decimal.Decimal(six.text_type(value).strip())
context = decimal.getcontext().copy() quantized = self.quantize(value)
context.prec = self.max_digits
quantized = value.quantize(
decimal.Decimal('.1') ** self.decimal_places,
context=context
)
if not self.coerce_to_string: if not self.coerce_to_string:
return quantized return quantized
return '{0:f}'.format(quantized) return '{0:f}'.format(quantized)
def quantize(self, value):
"""
Quantize the decimal value to the configured precision.
"""
context = decimal.getcontext().copy()
context.prec = self.max_digits
return value.quantize(
decimal.Decimal('.1') ** self.decimal_places,
context=context)
# Date & time fields... # Date & time fields...