Skip to content

Commit 7fbdeb4

Browse files
committed
[1.2.X] Migrated defer doctests. Thanks to Alex Gaynor.
Backport of r13777 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13794 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 592288f commit 7fbdeb4

File tree

2 files changed

+138
-163
lines changed

2 files changed

+138
-163
lines changed

tests/modeltests/defer/models.py

Lines changed: 1 addition & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
from django.db import models
6-
from django.db.models.query_utils import DeferredAttribute
6+
77

88
class Secondary(models.Model):
99
first = models.CharField(max_length=50)
@@ -22,165 +22,3 @@ class Child(Primary):
2222

2323
class BigChild(Primary):
2424
other = models.CharField(max_length=50)
25-
26-
def count_delayed_fields(obj, debug=False):
27-
"""
28-
Returns the number of delayed attributes on the given model instance.
29-
"""
30-
count = 0
31-
for field in obj._meta.fields:
32-
if isinstance(obj.__class__.__dict__.get(field.attname),
33-
DeferredAttribute):
34-
if debug:
35-
print field.name, field.attname
36-
count += 1
37-
return count
38-
39-
40-
__test__ = {"API_TEST": """
41-
To all outward appearances, instances with deferred fields look the same as
42-
normal instances when we examine attribute values. Therefore we test for the
43-
number of deferred fields on returned instances (by poking at the internals),
44-
as a way to observe what is going on.
45-
46-
>>> s1 = Secondary.objects.create(first="x1", second="y1")
47-
>>> p1 = Primary.objects.create(name="p1", value="xx", related=s1)
48-
49-
>>> qs = Primary.objects.all()
50-
51-
>>> count_delayed_fields(qs.defer('name')[0])
52-
1
53-
>>> count_delayed_fields(qs.only('name')[0])
54-
2
55-
>>> count_delayed_fields(qs.defer('related__first')[0])
56-
0
57-
>>> obj = qs.select_related().only('related__first')[0]
58-
>>> count_delayed_fields(obj)
59-
2
60-
>>> obj.related_id == s1.pk
61-
True
62-
>>> count_delayed_fields(qs.defer('name').extra(select={'a': 1})[0])
63-
1
64-
>>> count_delayed_fields(qs.extra(select={'a': 1}).defer('name')[0])
65-
1
66-
>>> count_delayed_fields(qs.defer('name').defer('value')[0])
67-
2
68-
>>> count_delayed_fields(qs.only('name').only('value')[0])
69-
2
70-
>>> count_delayed_fields(qs.only('name').defer('value')[0])
71-
2
72-
>>> count_delayed_fields(qs.only('name', 'value').defer('value')[0])
73-
2
74-
>>> count_delayed_fields(qs.defer('name').only('value')[0])
75-
2
76-
>>> obj = qs.only()[0]
77-
>>> count_delayed_fields(qs.defer(None)[0])
78-
0
79-
>>> count_delayed_fields(qs.only('name').defer(None)[0])
80-
0
81-
82-
User values() won't defer anything (you get the full list of dictionaries
83-
back), but it still works.
84-
>>> qs.defer('name').values()[0] == {'id': p1.id, 'name': u'p1', 'value': 'xx', 'related_id': s1.id}
85-
True
86-
>>> qs.only('name').values()[0] == {'id': p1.id, 'name': u'p1', 'value': 'xx', 'related_id': s1.id}
87-
True
88-
89-
Using defer() and only() with get() is also valid.
90-
>>> count_delayed_fields(qs.defer('name').get(pk=p1.pk))
91-
1
92-
>>> count_delayed_fields(qs.only('name').get(pk=p1.pk))
93-
2
94-
95-
# KNOWN NOT TO WORK: >>> count_delayed_fields(qs.only('name').select_related('related')[0])
96-
# KNOWN NOT TO WORK >>> count_delayed_fields(qs.defer('related').select_related('related')[0])
97-
98-
# Saving models with deferred fields is possible (but inefficient, since every
99-
# field has to be retrieved first).
100-
101-
>>> obj = Primary.objects.defer("value").get(name="p1")
102-
>>> obj.name = "a new name"
103-
>>> obj.save()
104-
>>> Primary.objects.all()
105-
[<Primary: a new name>]
106-
107-
# Regression for #10572 - A subclass with no extra fields can defer fields from the base class
108-
>>> _ = Child.objects.create(name="c1", value="foo", related=s1)
109-
110-
# You can defer a field on a baseclass when the subclass has no fields
111-
>>> obj = Child.objects.defer("value").get(name="c1")
112-
>>> count_delayed_fields(obj)
113-
1
114-
>>> obj.name
115-
u"c1"
116-
>>> obj.value
117-
u"foo"
118-
>>> obj.name = "c2"
119-
>>> obj.save()
120-
121-
# You can retrive a single column on a base class with no fields
122-
>>> obj = Child.objects.only("name").get(name="c2")
123-
>>> count_delayed_fields(obj)
124-
3
125-
>>> obj.name
126-
u"c2"
127-
>>> obj.value
128-
u"foo"
129-
>>> obj.name = "cc"
130-
>>> obj.save()
131-
132-
>>> _ = BigChild.objects.create(name="b1", value="foo", related=s1, other="bar")
133-
134-
# You can defer a field on a baseclass
135-
>>> obj = BigChild.objects.defer("value").get(name="b1")
136-
>>> count_delayed_fields(obj)
137-
1
138-
>>> obj.name
139-
u"b1"
140-
>>> obj.value
141-
u"foo"
142-
>>> obj.other
143-
u"bar"
144-
>>> obj.name = "b2"
145-
>>> obj.save()
146-
147-
# You can defer a field on a subclass
148-
>>> obj = BigChild.objects.defer("other").get(name="b2")
149-
>>> count_delayed_fields(obj)
150-
1
151-
>>> obj.name
152-
u"b2"
153-
>>> obj.value
154-
u"foo"
155-
>>> obj.other
156-
u"bar"
157-
>>> obj.name = "b3"
158-
>>> obj.save()
159-
160-
# You can retrieve a single field on a baseclass
161-
>>> obj = BigChild.objects.only("name").get(name="b3")
162-
>>> count_delayed_fields(obj)
163-
4
164-
>>> obj.name
165-
u"b3"
166-
>>> obj.value
167-
u"foo"
168-
>>> obj.other
169-
u"bar"
170-
>>> obj.name = "b4"
171-
>>> obj.save()
172-
173-
# You can retrieve a single field on a baseclass
174-
>>> obj = BigChild.objects.only("other").get(name="b4")
175-
>>> count_delayed_fields(obj)
176-
4
177-
>>> obj.name
178-
u"b4"
179-
>>> obj.value
180-
u"foo"
181-
>>> obj.other
182-
u"bar"
183-
>>> obj.name = "bb"
184-
>>> obj.save()
185-
186-
"""}

tests/modeltests/defer/tests.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
from django.db.models.query_utils import DeferredAttribute
2+
from django.test import TestCase
3+
4+
from models import Secondary, Primary, Child, BigChild
5+
6+
7+
class DeferTests(TestCase):
8+
def assert_delayed(self, obj, num):
9+
count = 0
10+
for field in obj._meta.fields:
11+
if isinstance(obj.__class__.__dict__.get(field.attname),
12+
DeferredAttribute):
13+
count += 1
14+
self.assertEqual(count, num)
15+
16+
def test_defer(self):
17+
# To all outward appearances, instances with deferred fields look the
18+
# same as normal instances when we examine attribute values. Therefore
19+
# we test for the number of deferred fields on returned instances (by
20+
# poking at the internals), as a way to observe what is going on.
21+
22+
s1 = Secondary.objects.create(first="x1", second="y1")
23+
p1 = Primary.objects.create(name="p1", value="xx", related=s1)
24+
25+
qs = Primary.objects.all()
26+
27+
self.assert_delayed(qs.defer("name")[0], 1)
28+
self.assert_delayed(qs.only("name")[0], 2)
29+
self.assert_delayed(qs.defer("related__first")[0], 0)
30+
31+
obj = qs.select_related().only("related__first")[0]
32+
self.assert_delayed(obj, 2)
33+
34+
self.assertEqual(obj.related_id, s1.pk)
35+
36+
self.assert_delayed(qs.defer("name").extra(select={"a": 1})[0], 1)
37+
self.assert_delayed(qs.extra(select={"a": 1}).defer("name")[0], 1)
38+
self.assert_delayed(qs.defer("name").defer("value")[0], 2)
39+
self.assert_delayed(qs.only("name").only("value")[0], 2)
40+
self.assert_delayed(qs.only("name").defer("value")[0], 2)
41+
self.assert_delayed(qs.only("name", "value").defer("value")[0], 2)
42+
self.assert_delayed(qs.defer("name").only("value")[0], 2)
43+
44+
obj = qs.only()[0]
45+
self.assert_delayed(qs.defer(None)[0], 0)
46+
self.assert_delayed(qs.only("name").defer(None)[0], 0)
47+
48+
# User values() won't defer anything (you get the full list of
49+
# dictionaries back), but it still works.
50+
self.assertEqual(qs.defer("name").values()[0], {
51+
"id": p1.id,
52+
"name": "p1",
53+
"value": "xx",
54+
"related_id": s1.id,
55+
})
56+
self.assertEqual(qs.only("name").values()[0], {
57+
"id": p1.id,
58+
"name": "p1",
59+
"value": "xx",
60+
"related_id": s1.id,
61+
})
62+
63+
# Using defer() and only() with get() is also valid.
64+
self.assert_delayed(qs.defer("name").get(pk=p1.pk), 1)
65+
self.assert_delayed(qs.only("name").get(pk=p1.pk), 2)
66+
67+
# DOES THIS WORK?
68+
self.assert_delayed(qs.only("name").select_related("related")[0], 1)
69+
self.assert_delayed(qs.defer("related").select_related("related")[0], 0)
70+
71+
# Saving models with deferred fields is possible (but inefficient,
72+
# since every field has to be retrieved first).
73+
obj = Primary.objects.defer("value").get(name="p1")
74+
obj.name = "a new name"
75+
obj.save()
76+
self.assertQuerysetEqual(
77+
Primary.objects.all(), [
78+
"a new name",
79+
],
80+
lambda p: p.name
81+
)
82+
83+
# Regression for #10572 - A subclass with no extra fields can defer
84+
# fields from the base class
85+
Child.objects.create(name="c1", value="foo", related=s1)
86+
# You can defer a field on a baseclass when the subclass has no fields
87+
obj = Child.objects.defer("value").get(name="c1")
88+
self.assert_delayed(obj, 1)
89+
self.assertEqual(obj.name, "c1")
90+
self.assertEqual(obj.value, "foo")
91+
obj.name = "c2"
92+
obj.save()
93+
94+
# You can retrive a single column on a base class with no fields
95+
obj = Child.objects.only("name").get(name="c2")
96+
self.assert_delayed(obj, 3)
97+
self.assertEqual(obj.name, "c2")
98+
self.assertEqual(obj.value, "foo")
99+
obj.name = "cc"
100+
obj.save()
101+
102+
BigChild.objects.create(name="b1", value="foo", related=s1, other="bar")
103+
# You can defer a field on a baseclass
104+
obj = BigChild.objects.defer("value").get(name="b1")
105+
self.assert_delayed(obj, 1)
106+
self.assertEqual(obj.name, "b1")
107+
self.assertEqual(obj.value, "foo")
108+
self.assertEqual(obj.other, "bar")
109+
obj.name = "b2"
110+
obj.save()
111+
112+
# You can defer a field on a subclass
113+
obj = BigChild.objects.defer("other").get(name="b2")
114+
self.assert_delayed(obj, 1)
115+
self.assertEqual(obj.name, "b2")
116+
self.assertEqual(obj.value, "foo")
117+
self.assertEqual(obj.other, "bar")
118+
obj.name = "b3"
119+
obj.save()
120+
121+
# You can retrieve a single field on a baseclass
122+
obj = BigChild.objects.only("name").get(name="b3")
123+
self.assert_delayed(obj, 4)
124+
self.assertEqual(obj.name, "b3")
125+
self.assertEqual(obj.value, "foo")
126+
self.assertEqual(obj.other, "bar")
127+
obj.name = "b4"
128+
obj.save()
129+
130+
# You can retrieve a single field on a baseclass
131+
obj = BigChild.objects.only("other").get(name="b4")
132+
self.assert_delayed(obj, 4)
133+
self.assertEqual(obj.name, "b4")
134+
self.assertEqual(obj.value, "foo")
135+
self.assertEqual(obj.other, "bar")
136+
obj.name = "bb"
137+
obj.save()

0 commit comments

Comments
 (0)