summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamriddha9619 <sumitkumartripathi0@gmail.com>2026-01-20 01:38:34 +0530
committerJacob Walls <jacobtylerwalls@gmail.com>2026-01-28 17:04:39 -0500
commit2831eaed797627e6e6410b06f74dadeb63316e09 (patch)
tree2662cec2d329d5407be113b9c8bb25d149c5a884
parente61a54d306ec069826b53bfec0b56d9ab3199257 (diff)
Fixed #36233 -- Avoided quantizing integers stored in DecimalField on SQLite.
Co-authored-by: Simon Charette <charette.s@gmail.com> Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
-rw-r--r--django/db/backends/sqlite3/operations.py11
-rw-r--r--tests/model_fields/models.py1
-rw-r--r--tests/model_fields/test_decimalfield.py18
3 files changed, 27 insertions, 3 deletions
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 23c17054d2..18ff204ae3 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -300,10 +300,15 @@ class DatabaseOperations(BaseDatabaseOperations):
value = parse_time(value)
return value
+ @staticmethod
+ def _create_decimal(value):
+ if isinstance(value, (int, str)):
+ return decimal.Decimal(value)
+ return decimal.Context(prec=15).create_decimal_from_float(value)
+
def get_decimalfield_converter(self, expression):
# SQLite stores only 15 significant digits. Digits coming from
# float inaccuracy must be removed.
- create_decimal = decimal.Context(prec=15).create_decimal_from_float
if isinstance(expression, Col):
quantize_value = decimal.Decimal(1).scaleb(
-expression.output_field.decimal_places
@@ -311,7 +316,7 @@ class DatabaseOperations(BaseDatabaseOperations):
def converter(value, expression, connection):
if value is not None:
- return create_decimal(value).quantize(
+ return self._create_decimal(value).quantize(
quantize_value, context=expression.output_field.context
)
@@ -319,7 +324,7 @@ class DatabaseOperations(BaseDatabaseOperations):
def converter(value, expression, connection):
if value is not None:
- return create_decimal(value)
+ return self._create_decimal(value)
return converter
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
index cdf3c00080..1d8a447dee 100644
--- a/tests/model_fields/models.py
+++ b/tests/model_fields/models.py
@@ -102,6 +102,7 @@ class Choiceful(models.Model):
class BigD(models.Model):
d = models.DecimalField(max_digits=32, decimal_places=30)
+ large_int = models.DecimalField(max_digits=16, decimal_places=0, null=True)
class FloatModel(models.Model):
diff --git a/tests/model_fields/test_decimalfield.py b/tests/model_fields/test_decimalfield.py
index 17f59674e8..bab9a39c19 100644
--- a/tests/model_fields/test_decimalfield.py
+++ b/tests/model_fields/test_decimalfield.py
@@ -5,6 +5,7 @@ from unittest import mock
from django.core import validators
from django.core.exceptions import ValidationError
from django.db import connection, models
+from django.db.models import Max
from django.test import TestCase
from .models import BigD, Foo
@@ -140,3 +141,20 @@ class DecimalFieldTests(TestCase):
obj = Foo.objects.create(a="bar", d=Decimal("8.320"))
obj.refresh_from_db()
self.assertEqual(obj.d.compare_total(Decimal("8.320")), Decimal("0"))
+
+ def test_large_integer_precision(self):
+ large_int_val = Decimal("9999999999999999")
+ obj = BigD.objects.create(large_int=large_int_val, d=Decimal("0"))
+ obj.refresh_from_db()
+ self.assertEqual(obj.large_int, large_int_val)
+
+ def test_large_integer_precision_aggregation(self):
+ large_int_val = Decimal("9999999999999999")
+ BigD.objects.create(large_int=large_int_val, d=Decimal("0"))
+ result = BigD.objects.aggregate(max_val=Max("large_int"))
+ self.assertEqual(result["max_val"], large_int_val)
+
+ def test_roundtrip_integer_with_trailing_zeros(self):
+ obj = Foo.objects.create(a="bar", d=Decimal("8"))
+ obj.refresh_from_db()
+ self.assertEqual(obj.d.compare_total(Decimal("8.000")), Decimal("0"))