Author: russellm
Date: 2009-02-16 06:29:31 -0600 (Mon, 16 Feb 2009)
New Revision: 9838

Modified:
   django/trunk/django/db/models/query.py
   django/trunk/django/db/models/sql/query.py
   django/trunk/tests/regressiontests/aggregation_regress/models.py
Log:
Fixed #10132 -- Corrected the interaction of extra() queries with the values() 
clause. Thanks to Glen Maynard for the report.

Modified: django/trunk/django/db/models/query.py
===================================================================
--- django/trunk/django/db/models/query.py      2009-02-16 12:28:37 UTC (rev 
9837)
+++ django/trunk/django/db/models/query.py      2009-02-16 12:29:31 UTC (rev 
9838)
@@ -698,7 +698,7 @@
         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 @@
         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))
 

Modified: django/trunk/django/db/models/sql/query.py
===================================================================
--- django/trunk/django/db/models/sql/query.py  2009-02-16 12:28:37 UTC (rev 
9837)
+++ django/trunk/django/db/models/sql/query.py  2009-02-16 12:29:31 UTC (rev 
9838)
@@ -68,7 +68,7 @@
         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 @@
         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 @@
         # 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 @@
                 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 @@
         """
         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 @@
             # 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 @@
         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,

Modified: django/trunk/tests/regressiontests/aggregation_regress/models.py
===================================================================
--- django/trunk/tests/regressiontests/aggregation_regress/models.py    
2009-02-16 12:28:37 UTC (rev 9837)
+++ django/trunk/tests/regressiontests/aggregation_regress/models.py    
2009-02-16 12:29:31 UTC (rev 9838)
@@ -200,6 +200,13 @@
 >>> 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'))


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to