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