Skip to content

Improve DecimalField for easier subclassing. #2695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,10 +757,8 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=

def to_internal_value(self, data):
"""
Validates that the input is a decimal number. Returns a Decimal
instance. Returns None for empty values. Ensures that there are no more
than max_digits in the number, and no more than decimal_places digits
after the decimal point.
Validate that the input is a decimal number and return a Decimal
instance.
"""
data = smart_text(data).strip()
if len(data) > self.MAX_STRING_LENGTH:
Expand All @@ -780,6 +778,16 @@ def to_internal_value(self, data):
if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')):
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()
decimals = abs(exponent)
# digittuple doesn't include any leading zeros.
Expand All @@ -805,16 +813,22 @@ def to_representation(self, value):
if not isinstance(value, decimal.Decimal):
value = decimal.Decimal(six.text_type(value).strip())

context = decimal.getcontext().copy()
context.prec = self.max_digits
quantized = value.quantize(
decimal.Decimal('.1') ** self.decimal_places,
context=context
)
quantized = self.quantize(value)

if not self.coerce_to_string:
return 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...

Expand Down