diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index ee48a02d92d..2060b0c7b18 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1508,6 +1508,10 @@ class DecimalField(Field): validators.DecimalValidator(self.max_digits, self.decimal_places) ] + @cached_property + def context(self): + return decimal.Context(prec=self.max_digits) + def deconstruct(self): name, path, args, kwargs = super().deconstruct() if self.max_digits is not None: @@ -1522,6 +1526,8 @@ class DecimalField(Field): def to_python(self, value): if value is None: return value + if isinstance(value, float): + return self.context.create_decimal_from_float(value) try: return decimal.Decimal(value) except decimal.InvalidOperation: diff --git a/tests/model_fields/test_decimalfield.py b/tests/model_fields/test_decimalfield.py index 2f4540c81d3..5163d8188b8 100644 --- a/tests/model_fields/test_decimalfield.py +++ b/tests/model_fields/test_decimalfield.py @@ -15,6 +15,12 @@ class DecimalFieldTests(TestCase): f = models.DecimalField(max_digits=4, decimal_places=2) self.assertEqual(f.to_python(3), Decimal('3')) self.assertEqual(f.to_python('3.14'), Decimal('3.14')) + # to_python() converts floats and honors max_digits. + self.assertEqual(f.to_python(3.1415926535897), Decimal('3.142')) + self.assertEqual(f.to_python(2.4), Decimal('2.400')) + # Uses default rounding of ROUND_HALF_EVEN. + self.assertEqual(f.to_python(2.0625), Decimal('2.062')) + self.assertEqual(f.to_python(2.1875), Decimal('2.188')) with self.assertRaises(ValidationError): f.to_python('abc')