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"))