diff options
| author | Florian Hahn <flo@fhahn.com> | 2013-02-06 00:11:28 +0100 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2013-06-18 23:56:51 +0300 |
| commit | 2f35c6f10fcbae541691207fb0c0560a13b754fc (patch) | |
| tree | 5bae77807c3e715fcb08067f69b2aced7835b833 /django/db/models/sql/compiler.py | |
| parent | 9da9b3eb0454fa3dea228b16c6e35b01db5eee69 (diff) | |
Fixed #14930 -- values_list() failure on qs ordered by extra column
Thanks lsaffre for the report and simon29, vicould, and Florian Hahn
for the patch.
Some changes done by committer.
Diffstat (limited to 'django/db/models/sql/compiler.py')
| -rw-r--r-- | django/db/models/sql/compiler.py | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 77083372e0..f70750abed 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -22,6 +22,12 @@ class SQLCompiler(object): self.connection = connection self.using = using self.quote_cache = {} + # When ordering a queryset with distinct on a column not part of the + # select set, the ordering column needs to be added to the select + # clause. This information is needed both in SQL construction and + # masking away the ordering selects from the returned row. + self.ordering_aliases = [] + self.ordering_params = [] def pre_sql_setup(self): """ @@ -74,7 +80,7 @@ class SQLCompiler(object): # another run of it. self.refcounts_before = self.query.alias_refcount.copy() out_cols, s_params = self.get_columns(with_col_aliases) - ordering, ordering_group_by = self.get_ordering() + ordering, o_params, ordering_group_by = self.get_ordering() distinct_fields = self.get_distinct() @@ -95,9 +101,10 @@ class SQLCompiler(object): if self.query.distinct: result.append(self.connection.ops.distinct_sql(distinct_fields)) - - result.append(', '.join(out_cols + self.query.ordering_aliases)) + params.extend(o_params) + result.append(', '.join(out_cols + self.ordering_aliases)) params.extend(s_params) + params.extend(self.ordering_params) result.append('FROM') result.extend(from_) @@ -319,7 +326,6 @@ class SQLCompiler(object): result.append("%s.%s" % (qn(alias), qn2(col))) return result - def get_ordering(self): """ Returns a tuple containing a list representing the SQL elements in the @@ -357,7 +363,9 @@ class SQLCompiler(object): # the table/column pairs we use and discard any after the first use. processed_pairs = set() - for field in ordering: + params = [] + ordering_params = [] + for pos, field in enumerate(ordering): if field == '?': result.append(self.connection.ops.random_function_sql()) continue @@ -384,7 +392,7 @@ class SQLCompiler(object): if not distinct or elt in select_aliases: result.append('%s %s' % (elt, order)) group_by.append((elt, [])) - elif get_order_dir(field)[0] not in self.query.extra_select: + elif get_order_dir(field)[0] not in self.query.extra: # 'col' is of the form 'field' or 'field1__field2' or # '-field1__field2__field', etc. for table, cols, order in self.find_ordering_name(field, @@ -399,12 +407,19 @@ class SQLCompiler(object): group_by.append((elt, [])) else: elt = qn2(col) - if distinct and col not in select_aliases: - ordering_aliases.append(elt) + if col not in self.query.extra_select: + sql = "(%s) AS %s" % (self.query.extra[col][0], elt) + ordering_aliases.append(sql) + ordering_params.extend(self.query.extra[col][1]) + else: + if distinct and col not in select_aliases: + ordering_aliases.append(elt) + ordering_params.extend(params) result.append('%s %s' % (elt, order)) - group_by.append(self.query.extra_select[col]) - self.query.ordering_aliases = ordering_aliases - return result, group_by + group_by.append(self.query.extra[col]) + self.ordering_aliases = ordering_aliases + self.ordering_params = ordering_params + return result, params, group_by def find_ordering_name(self, name, opts, alias=None, default_order='ASC', already_seen=None): @@ -764,13 +779,13 @@ class SQLCompiler(object): if not result_type: return cursor if result_type == SINGLE: - if self.query.ordering_aliases: - return cursor.fetchone()[:-len(self.query.ordering_aliases)] + if self.ordering_aliases: + return cursor.fetchone()[:-len(self.ordering_aliases)] return cursor.fetchone() # The MULTI case. - if self.query.ordering_aliases: - result = order_modified_iter(cursor, len(self.query.ordering_aliases), + if self.ordering_aliases: + result = order_modified_iter(cursor, len(self.ordering_aliases), self.connection.features.empty_fetchmany_value) else: result = iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)), |
