DecimalField's validate_precision incorrectly calculates total_digits for decimals smaller than 1 #9762
-
The Steps to ReproduceThis script demonstrates the behavior. A from decimal import Decimal
from rest_framework.fields import DecimalField
from rest_framework.exceptions import ValidationError
validator = DecimalField(max_digits=3, decimal_places=5) # decimal_places is large to not interfere.
value = Decimal('0.0125')
print(f"Validating '{value}' with max_digits={validator.max_digits}...")
try:
validator.to_internal_value(value)
print("✅ SUCCESS: The value was correctly validated.")
except ValidationError as e:
print(f"❌ FAILED: The validator incorrectly rejected a valid value.")
print(f" Error: {e.detail}") Expected BehaviorThe script should execute without raising an exception, as
Actual BehaviorThe script raises a
AnalysisThe root cause is in the final # from rest_framework/fields.py
...
else:
# For values like 0.001234
total_digits = abs(exponent) # <-- This is the issue
... For This is inconsistent with the goal of validating significant digits. For example:
This behavior makes it difficult to use Possible SolutionA more accurate approach would be to calculate # A potential change in the else block:
total_digits = len(digittuple) Using I'd be happy to work on a pull request for this if the maintainers agree this is a bug. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
From the docs:
In your example, I haven't looked at the code yet, but what you describe with significant digits doesn't seem to match what is documented... |
Beta Was this translation helpful? Give feedback.
-
Good point, thanks. You're right — my first example violated the Let's try a different example that follows the documentation, but I believe still highlights the underlying ambiguity. # This configuration is valid (5 >= 4)
validator = DecimalField(max_digits=5, decimal_places=4)
# This value has 3 significant digits and 4 decimal places.
# It should be valid.
value = Decimal('0.0125') In this case, the validation passes. For Confusing InterpretationThis leads to a confusing interpretation of what
The core of the issue seems to be the definition of "total digits" for numbers less than 1. Is
Clarifying the intended behavior of |
Beta Was this translation helpful? Give feedback.
The argument is called
max_digits
, notsignificant_digits
, and I'm not sure where you got the "significant digits" from, but I don't think it's ever mentioned as such in our docs? That may be an important concept for decimal/scientific notation more generally, but it's not really what we're talking about here.I think the whole point is to have:
max_decimal_places
: how many number can be after the decimal: (XXX.XX ->max_decimal_places
= 2)max_digits
: maximum number of digits, whole + decimal (XXX.XX ->max_digits
= 5)max_whole_digits
to 3 hereAlso, this test pass now, so the value is now validated correctly (yes,
to_internal_value
takes a string and returns aDecimal
):