From d0f569b350bca89eeb186523d8905a6e31b5a947 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Wed, 27 Dec 2017 04:12:37 +0500 Subject: [PATCH] Refs #28459 -- Improved performance of loading DecimalField on SQLite. --- django/db/backends/sqlite3/base.py | 1 - django/db/backends/sqlite3/operations.py | 26 +++++++++++++++--------- django/db/models/fields/__init__.py | 14 ------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 44bd221f98..d15352dcc6 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -39,7 +39,6 @@ Database.register_converter("date", decoder(parse_date)) Database.register_converter("datetime", decoder(parse_datetime)) Database.register_converter("timestamp", decoder(parse_datetime)) Database.register_converter("TIMESTAMP", decoder(parse_datetime)) -Database.register_converter("decimal", decoder(decimal.Decimal)) Database.register_adapter(decimal.Decimal, backend_utils.rev_typecast_decimal) diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py index b58c344e6b..69744365a2 100644 --- a/django/db/backends/sqlite3/operations.py +++ b/django/db/backends/sqlite3/operations.py @@ -214,7 +214,7 @@ class DatabaseOperations(BaseDatabaseOperations): elif internal_type == 'TimeField': converters.append(self.convert_timefield_value) elif internal_type == 'DecimalField': - converters.append(self.convert_decimalfield_value) + converters.append(self.get_decimalfield_converter(expression)) elif internal_type == 'UUIDField': converters.append(self.convert_uuidfield_value) elif internal_type in ('NullBooleanField', 'BooleanField'): @@ -241,15 +241,21 @@ class DatabaseOperations(BaseDatabaseOperations): value = parse_time(value) return value - def convert_decimalfield_value(self, value, expression, connection): - if value is not None: - if not isinstance(expression, Col): - # SQLite stores only 15 significant digits. Digits coming from - # float inaccuracy must be removed. - return decimal.Context(prec=15).create_decimal_from_float(value) - value = expression.output_field.format_number(value) - return decimal.Decimal(value) - return 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) + + def converter(value, expression, connection): + if value is not None: + return create_decimal(value).quantize(quantize_value, context=expression.output_field.context) + else: + def converter(value, expression, connection): + if value is not None: + return create_decimal(value) + return converter def convert_uuidfield_value(self, value, expression, connection): if value is not None: diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 91336ed7d9..a67cf9b647 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1560,20 +1560,6 @@ class DecimalField(Field): params={'value': value}, ) - def format_number(self, value): - """ - Format a number into a string with the requisite number of digits and - decimal places. - """ - # Method moved to django.db.backends.utils. - # - # It is preserved because it is used by the oracle backend - # (django.db.backends.oracle.query), and also for - # backwards-compatibility with any external code which may have used - # this method. - from django.db.backends import utils - return utils.format_number(value, self.max_digits, self.decimal_places) - def get_db_prep_save(self, value, connection): return connection.ops.adapt_decimalfield_value(self.to_python(value), self.max_digits, self.decimal_places)