Skip to content

Commit e8cc948

Browse files
committed
Merge pull request #2695 from delinhabit/refactor-decimalfield
[enhancement] Refactored DecimalField to allow easier subclassing
2 parents 0c66c7c + 022c4d5 commit e8cc948

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

rest_framework/fields.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -775,10 +775,8 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=
775775

776776
def to_internal_value(self, data):
777777
"""
778-
Validates that the input is a decimal number. Returns a Decimal
779-
instance. Returns None for empty values. Ensures that there are no more
780-
than max_digits in the number, and no more than decimal_places digits
781-
after the decimal point.
778+
Validate that the input is a decimal number and return a Decimal
779+
instance.
782780
"""
783781
data = smart_text(data).strip()
784782
if len(data) > self.MAX_STRING_LENGTH:
@@ -798,6 +796,16 @@ def to_internal_value(self, data):
798796
if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')):
799797
self.fail('invalid')
800798

799+
return self.validate_precision(value)
800+
801+
def validate_precision(self, value):
802+
"""
803+
Ensure that there are no more than max_digits in the number, and no
804+
more than decimal_places digits after the decimal point.
805+
806+
Override this method to disable the precision validation for input
807+
values or to enhance it in any way you need to.
808+
"""
801809
sign, digittuple, exponent = value.as_tuple()
802810
decimals = exponent * decimal.Decimal(-1) if exponent < 0 else 0
803811

@@ -824,16 +832,22 @@ def to_representation(self, value):
824832
if not isinstance(value, decimal.Decimal):
825833
value = decimal.Decimal(six.text_type(value).strip())
826834

827-
context = decimal.getcontext().copy()
828-
context.prec = self.max_digits
829-
quantized = value.quantize(
830-
decimal.Decimal('.1') ** self.decimal_places,
831-
context=context
832-
)
835+
quantized = self.quantize(value)
836+
833837
if not self.coerce_to_string:
834838
return quantized
835839
return '{0:f}'.format(quantized)
836840

841+
def quantize(self, value):
842+
"""
843+
Quantize the decimal value to the configured precision.
844+
"""
845+
context = decimal.getcontext().copy()
846+
context.prec = self.max_digits
847+
return value.quantize(
848+
decimal.Decimal('.1') ** self.decimal_places,
849+
context=context)
850+
837851

838852
# Date & time fields...
839853

0 commit comments

Comments
 (0)