From e083c62f51f408aaacbf55684daf83c78d0d1bc1 Mon Sep 17 00:00:00 2001 From: VIZZARD-X Date: Fri, 16 Jan 2026 19:01:23 +0530 Subject: [PATCH] Fixed #36030 -- Fixed precision loss in division of Decimal literals on SQLite. Thanks Bob Kline for the review. --- django/db/models/expressions.py | 14 +++++++++++++- tests/expressions/tests.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 6b90a42cf1..baa91cc2c1 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -1141,7 +1141,7 @@ class Func(SQLiteNumericMixin, Expression): @deconstructible(path="django.db.models.Value") -class Value(SQLiteNumericMixin, Expression): +class Value(Expression): """Represent a wrapped value as a node within an expression.""" # Provide a default value for `for_save` in order to allow unresolved @@ -1182,6 +1182,18 @@ class Value(SQLiteNumericMixin, Expression): return "NULL", [] return "%s", [val] + def as_sqlite(self, compiler, connection, **extra_context): + sql, params = self.as_sql(compiler, connection, **extra_context) + try: + if self.output_field.get_internal_type() == "DecimalField": + if isinstance(self.value, Decimal): + sql = "(CAST(%s AS REAL))" % sql + else: + sql = "(CAST(%s AS NUMERIC))" % sql + except FieldError: + pass + return sql, params + def resolve_expression( self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False ): diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index 981d84e9e8..02126fa896 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -137,6 +137,16 @@ class BasicExpressionsTests(TestCase): ) self.assertEqual(companies["result"], 2395) + def test_decimal_division_literal_value(self): + """ + Division with a literal Decimal value preserves precision. + """ + num = Number.objects.create(integer=2) + obj = Number.objects.annotate( + val=F("integer") / Value(Decimal("3.0"), output_field=DecimalField()) + ).get(pk=num.pk) + self.assertAlmostEqual(obj.val, Decimal("0.6667"), places=4) + def test_annotate_values_filter(self): companies = ( Company.objects.annotate(