Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.2.X] Fixed #12687 -- fixed an issue with aggregates and counts in …

…conjunction with annotations where the QuerySet was provably empty. Backport of [14586].

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14587 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 03b111c6cc2a09ddf8eea50d8d430a305799e9be 1 parent 929b8ff
Alex Gaynor authored November 17, 2010
1  django/db/models/sql/aggregates.py
@@ -8,6 +8,7 @@ class AggregateField(object):
8 8
     """
9 9
     def __init__(self, internal_type):
10 10
         self.internal_type = internal_type
  11
+
11 12
     def get_internal_type(self):
12 13
         return self.internal_type
13 14
 
20  django/db/models/sql/query.py
@@ -337,7 +337,7 @@ def get_aggregation(self, using):
337 337
         # information but retrieves only the first row. Aggregate
338 338
         # over the subquery instead.
339 339
         if self.group_by is not None:
340  
-            from subqueries import AggregateQuery
  340
+            from django.db.models.sql.subqueries import AggregateQuery
341 341
             query = AggregateQuery(self.model)
342 342
 
343 343
             obj = self.clone()
@@ -349,7 +349,13 @@ def get_aggregation(self, using):
349 349
                     query.aggregate_select[alias] = aggregate
350 350
                     del obj.aggregate_select[alias]
351 351
 
352  
-            query.add_subquery(obj, using)
  352
+            try:
  353
+                query.add_subquery(obj, using)
  354
+            except EmptyResultSet:
  355
+                return dict(
  356
+                    (alias, None)
  357
+                    for alias in query.aggregate_select
  358
+                )
353 359
         else:
354 360
             query = self
355 361
             self.select = []
@@ -382,13 +388,19 @@ def get_count(self, using):
382 388
             # If a select clause exists, then the query has already started to
383 389
             # specify the columns that are to be returned.
384 390
             # In this case, we need to use a subquery to evaluate the count.
385  
-            from subqueries import AggregateQuery
  391
+            from django.db.models.sql.subqueries import AggregateQuery
386 392
             subquery = obj
387 393
             subquery.clear_ordering(True)
388 394
             subquery.clear_limits()
389 395
 
390 396
             obj = AggregateQuery(obj.model)
391  
-            obj.add_subquery(subquery, using=using)
  397
+            try:
  398
+                obj.add_subquery(subquery, using=using)
  399
+            except EmptyResultSet:
  400
+                # add_subquery evaluates the query, if it's an EmptyResultSet
  401
+                # then there are can be no results, and therefore there the
  402
+                # count is obviously 0
  403
+                return 0
392 404
 
393 405
         obj.add_count_column()
394 406
         number = obj.get_aggregation(using=using)[None]
1  django/db/models/sql/subqueries.py
@@ -10,6 +10,7 @@
10 10
 from django.db.models.sql.query import Query
11 11
 from django.db.models.sql.where import AND, Constraint
12 12
 
  13
+
13 14
 __all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery',
14 15
         'AggregateQuery']
15 16
 
18  tests/regressiontests/aggregation_regress/tests.py
@@ -641,6 +641,24 @@ def test_more_more_more(self):
641 641
             lambda: Book.objects.annotate(mean_age=Avg('authors__age')).annotate(Avg('mean_age'))
642 642
         )
643 643
 
  644
+    def test_empty_filter_count(self):
  645
+        self.assertEqual(
  646
+            Author.objects.filter(id__in=[]).annotate(Count("friends")).count(),
  647
+            0
  648
+        )
  649
+
  650
+    def test_empty_filter_aggregate(self):
  651
+        self.assertEqual(
  652
+            Author.objects.filter(id__in=[]).annotate(Count("friends")).aggregate(Count("pk")),
  653
+            {"pk__count": None}
  654
+        )
  655
+
  656
+    def test_annotate_and_join(self):
  657
+        self.assertEqual(
  658
+            Author.objects.annotate(c=Count("friends__name")).exclude(friends__name="Joe").count(),
  659
+            Author.objects.count()
  660
+        )
  661
+
644 662
     if run_stddev_tests():
645 663
         def test_stddev(self):
646 664
             self.assertEqual(

0 notes on commit 03b111c

Please sign in to comment.
Something went wrong with that request. Please try again.