Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.5.x] Fixed #16436 -- defer + annotate + select_related crash

Correctly calculate the ``aggregate_start`` offset from loaded fields,
if any are deferred, instead of ``self.query.select`` which includes all
fields on the model.

Backpatch of 69f7db1 from master.
  • Loading branch information...
commit b495c24375aa1fe0373727511cf81298337a1227 1 parent f8393ed
authored May 30, 2013 akaariai committed October 09, 2013
3  django/db/models/sql/compiler.py
@@ -775,7 +775,8 @@ def results_iter(self):
775 775
         for rows in self.execute_sql(MULTI):
776 776
             for row in rows:
777 777
                 if has_aggregate_select:
778  
-                    aggregate_start = len(self.query.extra_select) + len(self.query.select)
  778
+                    loaded_fields = self.query.get_loaded_field_names().get(self.query.model, set()) or self.query.select
  779
+                    aggregate_start = len(self.query.extra_select) + len(loaded_fields)
779 780
                     aggregate_end = aggregate_start + len(self.query.aggregate_select)
780 781
                 if resolve_columns:
781 782
                     if fields is None:
19  tests/modeltests/defer/models.py
@@ -28,3 +28,22 @@ class BigChild(Primary):
28 28
 class ChildProxy(Child):
29 29
     class Meta:
30 30
         proxy=True
  31
+
  32
+class Profile(models.Model):
  33
+    profile1 = models.TextField(default='profile1')
  34
+
  35
+class Location(models.Model):
  36
+    location1 = models.TextField(default='location1')
  37
+
  38
+class Item(models.Model):
  39
+    pass
  40
+
  41
+class Request(models.Model):
  42
+    profile = models.ForeignKey(Profile, null=True, blank=True)
  43
+    location = models.ForeignKey(Location)
  44
+    items = models.ManyToManyField(Item)
  45
+
  46
+    request1 = models.TextField(default='request1')
  47
+    request2 = models.TextField(default='request2')
  48
+    request3 = models.TextField(default='request3')
  49
+    request4 = models.TextField(default='request4')
17  tests/modeltests/defer/tests.py
... ...
@@ -1,9 +1,10 @@
1 1
 from __future__ import absolute_import
2 2
 
  3
+from django.db.models import Count
3 4
 from django.db.models.query_utils import DeferredAttribute, InvalidQuery
4 5
 from django.test import TestCase
5 6
 
6  
-from .models import Secondary, Primary, Child, BigChild, ChildProxy
  7
+from .models import Secondary, Primary, Child, BigChild, ChildProxy, Location, Request
7 8
 
8 9
 
9 10
 class DeferTests(TestCase):
@@ -183,3 +184,17 @@ def test_defer_inheritance_pk_chaining(self):
183 184
         with self.assertNumQueries(0):
184 185
             bc_deferred.id
185 186
         self.assertEqual(bc_deferred.pk, bc_deferred.id)
  187
+
  188
+class DeferAnnotateSelectRelatedTest(TestCase):
  189
+    def test_defer_annotate_select_related(self):
  190
+        location = Location.objects.create()
  191
+        Request.objects.create(location=location)
  192
+        self.assertIsInstance(list(Request.objects
  193
+            .annotate(Count('items')).select_related('profile', 'location')
  194
+            .only('profile', 'location')), list)
  195
+        self.assertIsInstance(list(Request.objects
  196
+            .annotate(Count('items')).select_related('profile', 'location')
  197
+            .only('profile__profile1', 'location__location1')), list)
  198
+        self.assertIsInstance(list(Request.objects
  199
+            .annotate(Count('items')).select_related('profile', 'location')
  200
+            .defer('request1', 'request2', 'request3', 'request4')), list)

0 notes on commit b495c24

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