Skip to content

Commit 47ccefe

Browse files
sir-sigurdtimgraham
authored andcommitted
Refs #28459 -- Improved performance of BaseExpression.convert_value().
1 parent d04b324 commit 47ccefe

File tree

1 file changed

+22
-9
lines changed

1 file changed

+22
-9
lines changed

django/db/models/expressions.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,18 @@ def __init__(self, output_field=None):
144144
if output_field is not None:
145145
self.output_field = output_field
146146

147+
def __getstate__(self):
148+
# This method required only for Python 3.4.
149+
state = self.__dict__.copy()
150+
state.pop('convert_value', None)
151+
return state
152+
147153
def get_db_converters(self, connection):
148-
return [self.convert_value] + self.output_field.get_db_converters(connection)
154+
return (
155+
[]
156+
if self.convert_value is self._convert_value_noop else
157+
[self.convert_value]
158+
) + self.output_field.get_db_converters(connection)
149159

150160
def get_source_expressions(self):
151161
return []
@@ -274,23 +284,26 @@ def _resolve_output_field(self):
274284
raise FieldError('Expression contains mixed types. You must set output_field.')
275285
return output_field
276286

277-
def convert_value(self, value, expression, connection):
287+
@staticmethod
288+
def _convert_value_noop(value, expression, connection):
289+
return value
290+
291+
@cached_property
292+
def convert_value(self):
278293
"""
279294
Expressions provide their own converters because users have the option
280295
of manually specifying the output_field which may be a different type
281296
from the one the database returns.
282297
"""
283298
field = self.output_field
284299
internal_type = field.get_internal_type()
285-
if value is None:
286-
return value
287-
elif internal_type == 'FloatField':
288-
return float(value)
300+
if internal_type == 'FloatField':
301+
return lambda value, expression, connection: None if value is None else float(value)
289302
elif internal_type.endswith('IntegerField'):
290-
return int(value)
303+
return lambda value, expression, connection: None if value is None else int(value)
291304
elif internal_type == 'DecimalField':
292-
return Decimal(value)
293-
return value
305+
return lambda value, expression, connection: None if value is None else Decimal(value)
306+
return self._convert_value_noop
294307

295308
def get_lookup(self, lookup):
296309
return self.output_field.get_lookup(lookup)

0 commit comments

Comments
 (0)