From 2d136ede8abd6876b33607eea094e6903eb77d77 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Tue, 1 Aug 2017 10:24:51 +0500 Subject: [PATCH] Fixed #28459 -- Improved performance of ValuesListIterable. --- django/db/models/query.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index 1984ba6006..aabd4d7a54 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -3,6 +3,7 @@ The main QuerySet implementation. This provides the public API for the ORM. """ import copy +import operator import sys import warnings from collections import OrderedDict, deque @@ -116,10 +117,8 @@ class ValuesListIterable(BaseIterable): query = queryset.query compiler = query.get_compiler(queryset.db) - if not query.extra_select and not query.annotation_select: - for row in compiler.results_iter(): - yield tuple(row) - else: + results = compiler.results_iter() + if queryset._fields: field_names = list(query.values_select) extra_names = list(query.extra_select) annotation_names = list(query.annotation_select) @@ -127,15 +126,13 @@ class ValuesListIterable(BaseIterable): # extra(select=...) cols are always at the start of the row. names = extra_names + field_names + annotation_names - if queryset._fields: + fields = list(queryset._fields) + [f for f in annotation_names if f not in queryset._fields] + if fields != names: # Reorder according to fields. - fields = list(queryset._fields) + [f for f in annotation_names if f not in queryset._fields] - else: - fields = names - - for row in compiler.results_iter(): - data = dict(zip(names, row)) - yield tuple(data[f] for f in fields) + index_map = {name: idx for idx, name in enumerate(names)} + rowfactory = operator.itemgetter(*[index_map[f] for f in fields]) + results = map(rowfactory, results) + return results class FlatValuesListIterable(BaseIterable):