1.9.30 sync.
[gae.git] / python / lib / django-1.5 / tests / modeltests / defer / tests.py
blobf0270479d46c7c21df6e6af08444c5ecf06d98f0
1 from __future__ import absolute_import
3 from django.db.models import Count
4 from django.db.models.query_utils import DeferredAttribute, InvalidQuery
5 from django.test import TestCase
7 from .models import Secondary, Primary, Child, BigChild, ChildProxy, Location, Request
10 class DeferTests(TestCase):
11 def assert_delayed(self, obj, num):
12 count = 0
13 for field in obj._meta.fields:
14 if isinstance(obj.__class__.__dict__.get(field.attname),
15 DeferredAttribute):
16 count += 1
17 self.assertEqual(count, num)
19 def test_defer(self):
20 # To all outward appearances, instances with deferred fields look the
21 # same as normal instances when we examine attribute values. Therefore
22 # we test for the number of deferred fields on returned instances (by
23 # poking at the internals), as a way to observe what is going on.
25 s1 = Secondary.objects.create(first="x1", second="y1")
26 p1 = Primary.objects.create(name="p1", value="xx", related=s1)
28 qs = Primary.objects.all()
30 self.assert_delayed(qs.defer("name")[0], 1)
31 self.assert_delayed(qs.only("name")[0], 2)
32 self.assert_delayed(qs.defer("related__first")[0], 0)
34 # Using 'pk' with only() should result in 3 deferred fields, namely all
35 # of them except the model's primary key see #15494
36 self.assert_delayed(qs.only("pk")[0], 3)
38 obj = qs.select_related().only("related__first")[0]
39 self.assert_delayed(obj, 2)
41 self.assertEqual(obj.related_id, s1.pk)
43 # You can use 'pk' with reverse foreign key lookups.
44 self.assert_delayed(s1.primary_set.all().only('pk')[0], 3)
46 self.assert_delayed(qs.defer("name").extra(select={"a": 1})[0], 1)
47 self.assert_delayed(qs.extra(select={"a": 1}).defer("name")[0], 1)
48 self.assert_delayed(qs.defer("name").defer("value")[0], 2)
49 self.assert_delayed(qs.only("name").only("value")[0], 2)
50 self.assert_delayed(qs.only("name").defer("value")[0], 2)
51 self.assert_delayed(qs.only("name", "value").defer("value")[0], 2)
52 self.assert_delayed(qs.defer("name").only("value")[0], 2)
54 obj = qs.only()[0]
55 self.assert_delayed(qs.defer(None)[0], 0)
56 self.assert_delayed(qs.only("name").defer(None)[0], 0)
58 # User values() won't defer anything (you get the full list of
59 # dictionaries back), but it still works.
60 self.assertEqual(qs.defer("name").values()[0], {
61 "id": p1.id,
62 "name": "p1",
63 "value": "xx",
64 "related_id": s1.id,
66 self.assertEqual(qs.only("name").values()[0], {
67 "id": p1.id,
68 "name": "p1",
69 "value": "xx",
70 "related_id": s1.id,
73 # Using defer() and only() with get() is also valid.
74 self.assert_delayed(qs.defer("name").get(pk=p1.pk), 1)
75 self.assert_delayed(qs.only("name").get(pk=p1.pk), 2)
77 # When we defer a field and also select_related it, the query is
78 # invalid and raises an exception.
79 with self.assertRaises(InvalidQuery):
80 qs.only("name").select_related("related")[0]
81 with self.assertRaises(InvalidQuery):
82 qs.defer("related").select_related("related")[0]
84 # With a depth-based select_related, all deferred ForeignKeys are
85 # deferred instead of traversed.
86 with self.assertNumQueries(3):
87 obj = qs.defer("related").select_related()[0]
88 self.assert_delayed(obj, 1)
89 self.assertEqual(obj.related.id, s1.pk)
91 # Saving models with deferred fields is possible (but inefficient,
92 # since every field has to be retrieved first).
93 obj = Primary.objects.defer("value").get(name="p1")
94 obj.name = "a new name"
95 obj.save()
96 self.assertQuerysetEqual(
97 Primary.objects.all(), [
98 "a new name",
100 lambda p: p.name
103 # Regression for #10572 - A subclass with no extra fields can defer
104 # fields from the base class
105 Child.objects.create(name="c1", value="foo", related=s1)
106 # You can defer a field on a baseclass when the subclass has no fields
107 obj = Child.objects.defer("value").get(name="c1")
108 self.assert_delayed(obj, 1)
109 self.assertEqual(obj.name, "c1")
110 self.assertEqual(obj.value, "foo")
111 obj.name = "c2"
112 obj.save()
114 # You can retrive a single column on a base class with no fields
115 obj = Child.objects.only("name").get(name="c2")
116 self.assert_delayed(obj, 3)
117 self.assertEqual(obj.name, "c2")
118 self.assertEqual(obj.value, "foo")
119 obj.name = "cc"
120 obj.save()
122 BigChild.objects.create(name="b1", value="foo", related=s1, other="bar")
123 # You can defer a field on a baseclass
124 obj = BigChild.objects.defer("value").get(name="b1")
125 self.assert_delayed(obj, 1)
126 self.assertEqual(obj.name, "b1")
127 self.assertEqual(obj.value, "foo")
128 self.assertEqual(obj.other, "bar")
129 obj.name = "b2"
130 obj.save()
132 # You can defer a field on a subclass
133 obj = BigChild.objects.defer("other").get(name="b2")
134 self.assert_delayed(obj, 1)
135 self.assertEqual(obj.name, "b2")
136 self.assertEqual(obj.value, "foo")
137 self.assertEqual(obj.other, "bar")
138 obj.name = "b3"
139 obj.save()
141 # You can retrieve a single field on a baseclass
142 obj = BigChild.objects.only("name").get(name="b3")
143 self.assert_delayed(obj, 4)
144 self.assertEqual(obj.name, "b3")
145 self.assertEqual(obj.value, "foo")
146 self.assertEqual(obj.other, "bar")
147 obj.name = "b4"
148 obj.save()
150 # You can retrieve a single field on a baseclass
151 obj = BigChild.objects.only("other").get(name="b4")
152 self.assert_delayed(obj, 4)
153 self.assertEqual(obj.name, "b4")
154 self.assertEqual(obj.value, "foo")
155 self.assertEqual(obj.other, "bar")
156 obj.name = "bb"
157 obj.save()
159 def test_defer_proxy(self):
161 Ensure select_related together with only on a proxy model behaves
162 as expected. See #17876.
164 related = Secondary.objects.create(first='x1', second='x2')
165 ChildProxy.objects.create(name='p1', value='xx', related=related)
166 children = ChildProxy.objects.all().select_related().only('id', 'name')
167 self.assertEqual(len(children), 1)
168 child = children[0]
169 self.assert_delayed(child, 2)
170 self.assertEqual(child.name, 'p1')
171 self.assertEqual(child.value, 'xx')
173 def test_defer_inheritance_pk_chaining(self):
175 When an inherited model is fetched from the DB, its PK is also fetched.
176 When getting the PK of the parent model it is useful to use the already
177 fetched parent model PK if it happens to be available. Tests that this
178 is done.
180 s1 = Secondary.objects.create(first="x1", second="y1")
181 bc = BigChild.objects.create(name="b1", value="foo", related=s1,
182 other="bar")
183 bc_deferred = BigChild.objects.only('name').get(pk=bc.pk)
184 with self.assertNumQueries(0):
185 bc_deferred.id
186 self.assertEqual(bc_deferred.pk, bc_deferred.id)
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)