Q:

Why is the Django decimal max_digits validation failing with strange behaviour?

I have a model field full_time_equivalent:
full_time_equivalent = models.DecimalField(
    max_digits=5,
    decimal_places=2,
    default=100,
    validators=[
        MinValueValidator(Decimal(0)),
        MaxValueValidator(Decimal(100))
    ]
)

To ensure that the validators fire I have override save with:
def save(self, *args, **kwargs):
    # Run validations
    self.full_clean()
    return super().save(*args, **kwargs)

With the following test:
    project2_membership = ProjectMembership(
        user=self.new_user,
        project=project2,
        is_project_manager=False,
        full_time_equivalent=10.01
    )

When I step into the validation the following value is shown and respective error:
Decimal('10.0099999999999997868371792719699442386627197265625')

django.core.exceptions.ValidationError: 
{'full_time_equivalent': ['Ensure that there are no more than 5 digits in total.']

What am I doing wrong?

A:

The decimal value 10.01 can't be expressed exactly as a float. When the value is converted to a decimal, you end up with Decimal('10.0099999999999997868371792719699442386627197265625'), which is very nearly equal to Decimal('10.01'), but fails your max_digits validation.
You can prevent the error by using the string '10.01' or the decimal Decimal('10.01') in your test.
from decimal import Decimal

project2_membership = ProjectMembership(
    user=self.new_user,
    project=project2,
    is_project_manager=False,
    full_time_equivalent=Decimal('10.01')
)

