summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/compiler.py66
1 files changed, 35 insertions, 31 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index db1e1131ad..f0a1611e9c 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -103,21 +103,12 @@ class SQLCompiler(object):
result.append('WHERE %s' % where)
params.extend(w_params)
- grouping, gb_params = self.get_grouping()
+ grouping, gb_params = self.get_grouping(ordering_group_by)
if grouping:
if distinct_fields:
raise NotImplementedError(
"annotate() + distinct(fields) not implemented.")
- if ordering:
- # If the backend can't group by PK (i.e., any database
- # other than MySQL), then any fields mentioned in the
- # ordering clause needs to be in the group by clause.
- if not self.connection.features.allows_group_by_pk:
- for col, col_params in ordering_group_by:
- if col not in grouping:
- grouping.append(str(col))
- gb_params.extend(col_params)
- else:
+ if not ordering:
ordering = self.connection.ops.force_no_ordering()
result.append('GROUP BY %s' % ', '.join(grouping))
params.extend(gb_params)
@@ -378,7 +369,7 @@ class SQLCompiler(object):
else:
order = asc
result.append('%s %s' % (field, order))
- group_by.append((field, []))
+ group_by.append((str(field), []))
continue
col, order = get_order_dir(field, asc)
if col in self.query.aggregate_select:
@@ -538,39 +529,52 @@ class SQLCompiler(object):
first = False
return result, []
- def get_grouping(self):
+ def get_grouping(self, ordering_group_by):
"""
Returns a tuple representing the SQL elements in the "group by" clause.
"""
qn = self.quote_name_unless_alias
result, params = [], []
if self.query.group_by is not None:
- if (len(self.query.model._meta.fields) == len(self.query.select) and
- self.connection.features.allows_group_by_pk):
+ select_cols = self.query.select + self.query.related_select_cols
+ # Just the column, not the fields.
+ select_cols = [s[0] for s in select_cols]
+ if (len(self.query.model._meta.fields) == len(self.query.select)
+ and self.connection.features.allows_group_by_pk):
self.query.group_by = [
(self.query.model._meta.db_table, self.query.model._meta.pk.column)
]
-
- group_by = self.query.group_by or []
-
- extra_selects = []
- for extra_select, extra_params in six.itervalues(self.query.extra_select):
- extra_selects.append(extra_select)
- params.extend(extra_params)
- select_cols = [s.col for s in self.query.select]
- related_select_cols = [s.col for s in self.query.related_select_cols]
- cols = (group_by + select_cols + related_select_cols + extra_selects)
+ select_cols = []
seen = set()
+ cols = self.query.group_by + select_cols
for col in cols:
- if col in seen:
- continue
- seen.add(col)
if isinstance(col, (list, tuple)):
- result.append('%s.%s' % (qn(col[0]), qn(col[1])))
+ sql = '%s.%s' % (qn(col[0]), qn(col[1]))
elif hasattr(col, 'as_sql'):
- result.append(col.as_sql(qn, self.connection))
+ sql = col.as_sql(qn, self.connection)
else:
- result.append('(%s)' % str(col))
+ sql = '(%s)' % str(col)
+ if sql not in seen:
+ result.append(sql)
+ seen.add(sql)
+
+ # Still, we need to add all stuff in ordering (except if the backend can
+ # group by just by PK).
+ if ordering_group_by and not self.connection.features.allows_group_by_pk:
+ for order, order_params in ordering_group_by:
+ # Even if we have seen the same SQL string, it might have
+ # different params, so, we add same SQL in "has params" case.
+ if order not in seen or params:
+ result.append(order)
+ params.extend(order_params)
+ seen.add(order)
+
+ # Unconditionally add the extra_select items.
+ for extra_select, extra_params in self.query.extra_select.values():
+ sql = '(%s)' % str(extra_select)
+ result.append(sql)
+ params.extend(extra_params)
+
return result, params
def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,