Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Migrated defer doctests. Thanks to Alex Gaynor.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13777 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit eb8b5dc2d4160b76c5a70ca732e56293d8f43729 1 parent 1d50f6a
Russell Keith-Magee authored September 12, 2010
164  tests/modeltests/defer/models.py
@@ -3,7 +3,7 @@
3 3
 """
4 4
 
5 5
 from django.db import models
6  
-from django.db.models.query_utils import DeferredAttribute
  6
+
7 7
 
8 8
 class Secondary(models.Model):
9 9
     first = models.CharField(max_length=50)
@@ -22,165 +22,3 @@ class Child(Primary):
22 22
 
23 23
 class BigChild(Primary):
24 24
     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  
-"""}
137  tests/modeltests/defer/tests.py
... ...
@@ -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 notes on commit eb8b5dc

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