summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTai Lee <tai.lee@3030.com.au>2013-05-30 08:16:09 +0300
committerAnssi Kääriäinen <akaariai@gmail.com>2013-10-09 13:55:32 +0300
commitb495c24375aa1fe0373727511cf81298337a1227 (patch)
tree5047fa3fa310edbef443bc5c87866ac7f9355247
parentf8393edb52e3dc73185f2496bfa08463fa4ffa09 (diff)
[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 69f7db153d8108dcef033207d49f4c80febf3d70 from master.
-rw-r--r--django/db/models/sql/compiler.py3
-rw-r--r--tests/modeltests/defer/models.py19
-rw-r--r--tests/modeltests/defer/tests.py17
3 files changed, 37 insertions, 2 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index ab249e50a0..50034bc369 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -775,7 +775,8 @@ class SQLCompiler(object):
for rows in self.execute_sql(MULTI):
for row in rows:
if has_aggregate_select:
- aggregate_start = len(self.query.extra_select) + len(self.query.select)
+ loaded_fields = self.query.get_loaded_field_names().get(self.query.model, set()) or self.query.select
+ aggregate_start = len(self.query.extra_select) + len(loaded_fields)
aggregate_end = aggregate_start + len(self.query.aggregate_select)
if resolve_columns:
if fields is None:
diff --git a/tests/modeltests/defer/models.py b/tests/modeltests/defer/models.py
index 0688cbc984..f42f865362 100644
--- a/tests/modeltests/defer/models.py
+++ b/tests/modeltests/defer/models.py
@@ -28,3 +28,22 @@ class BigChild(Primary):
class ChildProxy(Child):
class Meta:
proxy=True
+
+class Profile(models.Model):
+ profile1 = models.TextField(default='profile1')
+
+class Location(models.Model):
+ location1 = models.TextField(default='location1')
+
+class Item(models.Model):
+ pass
+
+class Request(models.Model):
+ profile = models.ForeignKey(Profile, null=True, blank=True)
+ location = models.ForeignKey(Location)
+ items = models.ManyToManyField(Item)
+
+ request1 = models.TextField(default='request1')
+ request2 = models.TextField(default='request2')
+ request3 = models.TextField(default='request3')
+ request4 = models.TextField(default='request4')
diff --git a/tests/modeltests/defer/tests.py b/tests/modeltests/defer/tests.py
index 50db5a76b4..f0270479d4 100644
--- a/tests/modeltests/defer/tests.py
+++ b/tests/modeltests/defer/tests.py
@@ -1,9 +1,10 @@
from __future__ import absolute_import
+from django.db.models import Count
from django.db.models.query_utils import DeferredAttribute, InvalidQuery
from django.test import TestCase
-from .models import Secondary, Primary, Child, BigChild, ChildProxy
+from .models import Secondary, Primary, Child, BigChild, ChildProxy, Location, Request
class DeferTests(TestCase):
@@ -183,3 +184,17 @@ class DeferTests(TestCase):
with self.assertNumQueries(0):
bc_deferred.id
self.assertEqual(bc_deferred.pk, bc_deferred.id)
+
+class DeferAnnotateSelectRelatedTest(TestCase):
+ def test_defer_annotate_select_related(self):
+ location = Location.objects.create()
+ Request.objects.create(location=location)
+ self.assertIsInstance(list(Request.objects
+ .annotate(Count('items')).select_related('profile', 'location')
+ .only('profile', 'location')), list)
+ self.assertIsInstance(list(Request.objects
+ .annotate(Count('items')).select_related('profile', 'location')
+ .only('profile__profile1', 'location__location1')), list)
+ self.assertIsInstance(list(Request.objects
+ .annotate(Count('items')).select_related('profile', 'location')
+ .defer('request1', 'request2', 'request3', 'request4')), list)