|
1 from operator import attrgetter |
|
2 |
|
3 from django.conf import settings |
|
4 from django.contrib.contenttypes.models import ContentType |
|
5 from django.contrib.sessions.backends.db import SessionStore |
|
6 from django.db import connection |
|
7 from django.db.models.loading import cache |
|
8 from django.test import TestCase |
|
9 |
|
10 from models import ResolveThis, Item, RelatedItem, Child, Leaf |
|
11 |
|
12 |
|
13 class DeferRegressionTest(TestCase): |
|
14 def assert_num_queries(self, n, func, *args, **kwargs): |
|
15 old_DEBUG = settings.DEBUG |
|
16 settings.DEBUG = True |
|
17 starting_queries = len(connection.queries) |
|
18 try: |
|
19 func(*args, **kwargs) |
|
20 finally: |
|
21 settings.DEBUG = old_DEBUG |
|
22 self.assertEqual(starting_queries + n, len(connection.queries)) |
|
23 |
|
24 def test_basic(self): |
|
25 # Deferred fields should really be deferred and not accidentally use |
|
26 # the field's default value just because they aren't passed to __init__ |
|
27 |
|
28 Item.objects.create(name="first", value=42) |
|
29 obj = Item.objects.only("name", "other_value").get(name="first") |
|
30 # Accessing "name" doesn't trigger a new database query. Accessing |
|
31 # "value" or "text" should. |
|
32 def test(): |
|
33 self.assertEqual(obj.name, "first") |
|
34 self.assertEqual(obj.other_value, 0) |
|
35 self.assert_num_queries(0, test) |
|
36 |
|
37 def test(): |
|
38 self.assertEqual(obj.value, 42) |
|
39 self.assert_num_queries(1, test) |
|
40 |
|
41 def test(): |
|
42 self.assertEqual(obj.text, "xyzzy") |
|
43 self.assert_num_queries(1, test) |
|
44 |
|
45 def test(): |
|
46 self.assertEqual(obj.text, "xyzzy") |
|
47 self.assert_num_queries(0, test) |
|
48 |
|
49 # Regression test for #10695. Make sure different instances don't |
|
50 # inadvertently share data in the deferred descriptor objects. |
|
51 i = Item.objects.create(name="no I'm first", value=37) |
|
52 items = Item.objects.only("value").order_by("-value") |
|
53 self.assertEqual(items[0].name, "first") |
|
54 self.assertEqual(items[1].name, "no I'm first") |
|
55 |
|
56 RelatedItem.objects.create(item=i) |
|
57 r = RelatedItem.objects.defer("item").get() |
|
58 self.assertEqual(r.item_id, i.id) |
|
59 self.assertEqual(r.item, i) |
|
60 |
|
61 # Some further checks for select_related() and inherited model |
|
62 # behaviour (regression for #10710). |
|
63 c1 = Child.objects.create(name="c1", value=42) |
|
64 c2 = Child.objects.create(name="c2", value=37) |
|
65 Leaf.objects.create(name="l1", child=c1, second_child=c2) |
|
66 |
|
67 obj = Leaf.objects.only("name", "child").select_related()[0] |
|
68 self.assertEqual(obj.child.name, "c1") |
|
69 |
|
70 self.assertQuerysetEqual( |
|
71 Leaf.objects.select_related().only("child__name", "second_child__name"), [ |
|
72 "l1", |
|
73 ], |
|
74 attrgetter("name") |
|
75 ) |
|
76 |
|
77 # Models instances with deferred fields should still return the same |
|
78 # content types as their non-deferred versions (bug #10738). |
|
79 ctype = ContentType.objects.get_for_model |
|
80 c1 = ctype(Item.objects.all()[0]) |
|
81 c2 = ctype(Item.objects.defer("name")[0]) |
|
82 c3 = ctype(Item.objects.only("name")[0]) |
|
83 self.assertTrue(c1 is c2 is c3) |
|
84 |
|
85 # Regression for #10733 - only() can be used on a model with two |
|
86 # foreign keys. |
|
87 results = Leaf.objects.only("name", "child", "second_child").select_related() |
|
88 self.assertEqual(results[0].child.name, "c1") |
|
89 self.assertEqual(results[0].second_child.name, "c2") |
|
90 |
|
91 results = Leaf.objects.only("name", "child", "second_child", "child__name", "second_child__name").select_related() |
|
92 self.assertEqual(results[0].child.name, "c1") |
|
93 self.assertEqual(results[0].second_child.name, "c2") |
|
94 |
|
95 # Test for #12163 - Pickling error saving session with unsaved model |
|
96 # instances. |
|
97 SESSION_KEY = '2b1189a188b44ad18c35e1baac6ceead' |
|
98 |
|
99 item = Item() |
|
100 item._deferred = False |
|
101 s = SessionStore(SESSION_KEY) |
|
102 s.clear() |
|
103 s["item"] = item |
|
104 s.save() |
|
105 |
|
106 s = SessionStore(SESSION_KEY) |
|
107 s.modified = True |
|
108 s.save() |
|
109 |
|
110 i2 = s["item"] |
|
111 self.assertFalse(i2._deferred) |
|
112 |
|
113 # Regression for #11936 - loading.get_models should not return deferred |
|
114 # models by default. |
|
115 klasses = sorted( |
|
116 cache.get_models(cache.get_app("defer_regress")), |
|
117 key=lambda klass: klass.__name__ |
|
118 ) |
|
119 self.assertEqual( |
|
120 klasses, [ |
|
121 Child, |
|
122 Item, |
|
123 Leaf, |
|
124 RelatedItem, |
|
125 ResolveThis, |
|
126 ] |
|
127 ) |
|
128 |
|
129 klasses = sorted( |
|
130 map( |
|
131 attrgetter("__name__"), |
|
132 cache.get_models( |
|
133 cache.get_app("defer_regress"), include_deferred=True |
|
134 ), |
|
135 ) |
|
136 ) |
|
137 self.assertEqual( |
|
138 klasses, [ |
|
139 "Child", |
|
140 "Child_Deferred_value", |
|
141 "Item", |
|
142 "Item_Deferred_name", |
|
143 "Item_Deferred_name_other_value_text", |
|
144 "Item_Deferred_name_other_value_value", |
|
145 "Item_Deferred_other_value_text_value", |
|
146 "Item_Deferred_text_value", |
|
147 "Leaf", |
|
148 "Leaf_Deferred_child_id_second_child_id_value", |
|
149 "Leaf_Deferred_name_value", |
|
150 "Leaf_Deferred_second_child_value", |
|
151 "Leaf_Deferred_value", |
|
152 "RelatedItem", |
|
153 "RelatedItem_Deferred_", |
|
154 "RelatedItem_Deferred_item_id", |
|
155 "ResolveThis", |
|
156 ] |
|
157 ) |
|
158 |
|
159 def test_resolve_columns(self): |
|
160 rt = ResolveThis.objects.create(num=5.0, name='Foobar') |
|
161 qs = ResolveThis.objects.defer('num') |
|
162 self.assertEqual(1, qs.count()) |
|
163 self.assertEqual('Foobar', qs[0].name) |