Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #10132 -- Corrected the interaction of extra() queries with the…

… values() clause. Thanks to Glen Maynard for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9838 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit fb64ea78968714929a75514ecd55fb5af1093697 1 parent 58ea6d4
@freakboy3742 freakboy3742 authored
View
3  django/db/models/query.py
@@ -698,7 +698,7 @@ def _setup_aggregate_query(self):
Prepare the query for computing a result that contains aggregate annotations.
"""
opts = self.model._meta
- if not self.query.group_by:
+ if self.query.group_by is None:
field_names = [f.attname for f in opts.fields]
self.query.add_fields(field_names, False)
self.query.set_group_by()
@@ -736,6 +736,7 @@ def iterator(self):
aggregate_names = self.query.aggregate_select.keys()
names = extra_names + field_names + aggregate_names
+
for row in self.query.results_iter():
yield dict(zip(names, row))
View
32 django/db/models/sql/query.py
@@ -68,7 +68,7 @@ def __init__(self, model, connection, where=WhereNode):
self.tables = [] # Aliases in the order they are created.
self.where = where()
self.where_class = where
- self.group_by = []
+ self.group_by = None
self.having = where()
self.order_by = []
self.low_mark, self.high_mark = 0, None # Used for offset/limit
@@ -177,7 +177,10 @@ def clone(self, klass=None, **kwargs):
obj.tables = self.tables[:]
obj.where = deepcopy(self.where)
obj.where_class = self.where_class
- obj.group_by = self.group_by[:]
+ if self.group_by is None:
+ obj.group_by = None
+ else:
+ obj.group_by = self.group_by[:]
obj.having = deepcopy(self.having)
obj.order_by = self.order_by[:]
obj.low_mark, obj.high_mark = self.low_mark, self.high_mark
@@ -272,7 +275,7 @@ def get_aggregation(self):
# If there is a group by clause, aggregating does not add useful
# information but retrieves only the first row. Aggregate
# over the subquery instead.
- if self.group_by:
+ if self.group_by is not None:
from subqueries import AggregateQuery
query = AggregateQuery(self.model, self.connection)
@@ -379,8 +382,8 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
result.append('AND')
result.append(' AND '.join(self.extra_where))
- if self.group_by:
- grouping = self.get_grouping()
+ grouping = self.get_grouping()
+ if grouping:
if ordering:
# If the backend can't group by PK (i.e., any database
# other than MySQL), then any fields mentioned in the
@@ -698,13 +701,15 @@ def get_grouping(self):
"""
qn = self.quote_name_unless_alias
result = []
- for col in self.group_by + self.related_select_cols:
- if isinstance(col, (list, tuple)):
- result.append('%s.%s' % (qn(col[0]), qn(col[1])))
- elif hasattr(col, 'as_sql'):
- result.append(col.as_sql(qn))
- else:
- result.append(str(col))
+ if self.group_by is not None:
+ group_by = self.group_by or []
+ for col in group_by + self.related_select_cols + self.extra_select.keys():
+ if isinstance(col, (list, tuple)):
+ result.append('%s.%s' % (qn(col[0]), qn(col[1])))
+ elif hasattr(col, 'as_sql'):
+ result.append(col.as_sql(qn))
+ else:
+ result.append(str(col))
return result
def get_ordering(self):
@@ -1224,7 +1229,7 @@ def add_aggregate(self, aggregate, model, alias, is_summary):
# Aggregate references a normal field
field_name = field_list[0]
source = opts.get_field(field_name)
- if not (self.group_by and is_summary):
+ if not (self.group_by is not None and is_summary):
# Only use a column alias if this is a
# standalone aggregate, or an annotation
col = (opts.db_table, source.column)
@@ -1816,6 +1821,7 @@ def set_group_by(self):
primary key, and the query would be equivalent, the optimization
will be made automatically.
"""
+ self.group_by = []
if self.connection.features.allows_group_by_pk:
if len(self.select) == len(self.model._meta.fields):
self.group_by.append('.'.join([self.model._meta.db_table,
View
7 tests/regressiontests/aggregation_regress/models.py
@@ -200,6 +200,13 @@ def __unicode__(self):
>>> sorted([(b.name, b.authors__age__avg, b.publisher.name, b.contact.name) for b in books])
[(u'Artificial Intelligence: A Modern Approach', 51.5, u'Prentice Hall', u'Peter Norvig'), (u'Practical Django Projects', 29.0, u'Apress', u'James Bennett'), (u'Python Web Development with Django', 30.3..., u'Prentice Hall', u'Jeffrey Forcier'), (u'Sams Teach Yourself Django in 24 Hours', 45.0, u'Sams', u'Brad Dayley')]
+# Regression for #10132 - If the values() clause only mentioned extra(select=) columns, those columns are used for grouping
+>>> Book.objects.extra(select={'pub':'publisher_id'}).values('pub').annotate(Count('id')).order_by('pub')
+[{'pub': 1, 'id__count': 2}, {'pub': 2, 'id__count': 1}, {'pub': 3, 'id__count': 2}, {'pub': 4, 'id__count': 1}]
+
+>>> Book.objects.extra(select={'pub':'publisher_id','foo':'pages'}).values('pub').annotate(Count('id')).order_by('pub')
+[{'pub': 1, 'id__count': 2}, {'pub': 2, 'id__count': 1}, {'pub': 3, 'id__count': 2}, {'pub': 4, 'id__count': 1}]
+
# Regression for #10199 - Aggregate calls clone the original query so the original query can still be used
>>> books = Book.objects.all()
>>> _ = books.aggregate(Avg('authors__age'))
Please sign in to comment.
Something went wrong with that request. Please try again.