tests.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. from operator import attrgetter
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.db import models
  4. from django.db.models import Count
  5. from django.test import TestCase
  6. from .models import (
  7. Base,
  8. Child,
  9. Derived,
  10. Feature,
  11. Item,
  12. ItemAndSimpleItem,
  13. Leaf,
  14. Location,
  15. OneToOneItem,
  16. Proxy,
  17. ProxyRelated,
  18. RelatedItem,
  19. Request,
  20. ResolveThis,
  21. SimpleItem,
  22. SpecialFeature,
  23. )
  24. class DeferRegressionTest(TestCase):
  25. def test_basic(self):
  26. # Deferred fields should really be deferred and not accidentally use
  27. # the field's default value just because they aren't passed to __init__
  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. with self.assertNumQueries(0):
  33. self.assertEqual(obj.name, "first")
  34. self.assertEqual(obj.other_value, 0)
  35. with self.assertNumQueries(1):
  36. self.assertEqual(obj.value, 42)
  37. with self.assertNumQueries(1):
  38. self.assertEqual(obj.text, "xyzzy")
  39. with self.assertNumQueries(0):
  40. self.assertEqual(obj.text, "xyzzy")
  41. # Regression test for #10695. Make sure different instances don't
  42. # inadvertently share data in the deferred descriptor objects.
  43. i = Item.objects.create(name="no I'm first", value=37)
  44. items = Item.objects.only("value").order_by("-value")
  45. self.assertEqual(items[0].name, "first")
  46. self.assertEqual(items[1].name, "no I'm first")
  47. RelatedItem.objects.create(item=i)
  48. r = RelatedItem.objects.defer("item").get()
  49. self.assertEqual(r.item_id, i.id)
  50. self.assertEqual(r.item, i)
  51. # Some further checks for select_related() and inherited model
  52. # behavior (regression for #10710).
  53. c1 = Child.objects.create(name="c1", value=42)
  54. c2 = Child.objects.create(name="c2", value=37)
  55. Leaf.objects.create(name="l1", child=c1, second_child=c2)
  56. obj = Leaf.objects.only("name", "child").select_related()[0]
  57. self.assertEqual(obj.child.name, "c1")
  58. self.assertQuerySetEqual(
  59. Leaf.objects.select_related().only("child__name", "second_child__name"),
  60. [
  61. "l1",
  62. ],
  63. attrgetter("name"),
  64. )
  65. # Models instances with deferred fields should still return the same
  66. # content types as their non-deferred versions (bug #10738).
  67. ctype = ContentType.objects.get_for_model
  68. c1 = ctype(Item.objects.all()[0])
  69. c2 = ctype(Item.objects.defer("name")[0])
  70. c3 = ctype(Item.objects.only("name")[0])
  71. self.assertTrue(c1 is c2 is c3)
  72. # Regression for #10733 - only() can be used on a model with two
  73. # foreign keys.
  74. results = Leaf.objects.only("name", "child", "second_child").select_related()
  75. self.assertEqual(results[0].child.name, "c1")
  76. self.assertEqual(results[0].second_child.name, "c2")
  77. results = Leaf.objects.only(
  78. "name", "child", "second_child", "child__name", "second_child__name"
  79. ).select_related()
  80. self.assertEqual(results[0].child.name, "c1")
  81. self.assertEqual(results[0].second_child.name, "c2")
  82. # Regression for #16409 - make sure defer() and only() work with annotate()
  83. self.assertIsInstance(
  84. list(SimpleItem.objects.annotate(Count("feature")).defer("name")), list
  85. )
  86. self.assertIsInstance(
  87. list(SimpleItem.objects.annotate(Count("feature")).only("name")), list
  88. )
  89. def test_ticket_16409(self):
  90. # Regression for #16409 - make sure defer() and only() work with annotate()
  91. self.assertIsInstance(
  92. list(SimpleItem.objects.annotate(Count("feature")).defer("name")), list
  93. )
  94. self.assertIsInstance(
  95. list(SimpleItem.objects.annotate(Count("feature")).only("name")), list
  96. )
  97. def test_ticket_23270(self):
  98. d = Derived.objects.create(text="foo", other_text="bar")
  99. with self.assertNumQueries(1):
  100. obj = Base.objects.select_related("derived").defer("text")[0]
  101. self.assertIsInstance(obj.derived, Derived)
  102. self.assertEqual("bar", obj.derived.other_text)
  103. self.assertNotIn("text", obj.__dict__)
  104. self.assertEqual(d.pk, obj.derived.base_ptr_id)
  105. def test_only_and_defer_usage_on_proxy_models(self):
  106. # Regression for #15790 - only() broken for proxy models
  107. proxy = Proxy.objects.create(name="proxy", value=42)
  108. msg = "QuerySet.only() return bogus results with proxy models"
  109. dp = Proxy.objects.only("other_value").get(pk=proxy.pk)
  110. self.assertEqual(dp.name, proxy.name, msg=msg)
  111. self.assertEqual(dp.value, proxy.value, msg=msg)
  112. # also test things with .defer()
  113. msg = "QuerySet.defer() return bogus results with proxy models"
  114. dp = Proxy.objects.defer("name", "text", "value").get(pk=proxy.pk)
  115. self.assertEqual(dp.name, proxy.name, msg=msg)
  116. self.assertEqual(dp.value, proxy.value, msg=msg)
  117. def test_resolve_columns(self):
  118. ResolveThis.objects.create(num=5.0, name="Foobar")
  119. qs = ResolveThis.objects.defer("num")
  120. self.assertEqual(1, qs.count())
  121. self.assertEqual("Foobar", qs[0].name)
  122. def test_reverse_one_to_one_relations(self):
  123. # Refs #14694. Test reverse relations which are known unique (reverse
  124. # side has o2ofield or unique FK) - the o2o case
  125. item = Item.objects.create(name="first", value=42)
  126. o2o = OneToOneItem.objects.create(item=item, name="second")
  127. self.assertEqual(len(Item.objects.defer("one_to_one_item__name")), 1)
  128. self.assertEqual(len(Item.objects.select_related("one_to_one_item")), 1)
  129. self.assertEqual(
  130. len(
  131. Item.objects.select_related("one_to_one_item").defer(
  132. "one_to_one_item__name"
  133. )
  134. ),
  135. 1,
  136. )
  137. self.assertEqual(
  138. len(Item.objects.select_related("one_to_one_item").defer("value")), 1
  139. )
  140. # Make sure that `only()` doesn't break when we pass in a unique relation,
  141. # rather than a field on the relation.
  142. self.assertEqual(len(Item.objects.only("one_to_one_item")), 1)
  143. with self.assertNumQueries(1):
  144. i = Item.objects.select_related("one_to_one_item")[0]
  145. self.assertEqual(i.one_to_one_item.pk, o2o.pk)
  146. self.assertEqual(i.one_to_one_item.name, "second")
  147. with self.assertNumQueries(1):
  148. i = Item.objects.select_related("one_to_one_item").defer(
  149. "value", "one_to_one_item__name"
  150. )[0]
  151. self.assertEqual(i.one_to_one_item.pk, o2o.pk)
  152. self.assertEqual(i.name, "first")
  153. with self.assertNumQueries(1):
  154. self.assertEqual(i.one_to_one_item.name, "second")
  155. with self.assertNumQueries(1):
  156. self.assertEqual(i.value, 42)
  157. def test_defer_with_select_related(self):
  158. item1 = Item.objects.create(name="first", value=47)
  159. item2 = Item.objects.create(name="second", value=42)
  160. simple = SimpleItem.objects.create(name="simple", value="23")
  161. ItemAndSimpleItem.objects.create(item=item1, simple=simple)
  162. obj = ItemAndSimpleItem.objects.defer("item").select_related("simple").get()
  163. self.assertEqual(obj.item, item1)
  164. self.assertEqual(obj.item_id, item1.id)
  165. obj.item = item2
  166. obj.save()
  167. obj = ItemAndSimpleItem.objects.defer("item").select_related("simple").get()
  168. self.assertEqual(obj.item, item2)
  169. self.assertEqual(obj.item_id, item2.id)
  170. def test_proxy_model_defer_with_select_related(self):
  171. # Regression for #22050
  172. item = Item.objects.create(name="first", value=47)
  173. RelatedItem.objects.create(item=item)
  174. # Defer fields with only()
  175. obj = ProxyRelated.objects.select_related().only("item__name")[0]
  176. with self.assertNumQueries(0):
  177. self.assertEqual(obj.item.name, "first")
  178. with self.assertNumQueries(1):
  179. self.assertEqual(obj.item.value, 47)
  180. def test_only_with_select_related(self):
  181. # Test for #17485.
  182. item = SimpleItem.objects.create(name="first", value=47)
  183. feature = Feature.objects.create(item=item)
  184. SpecialFeature.objects.create(feature=feature)
  185. qs = Feature.objects.only("item__name").select_related("item")
  186. self.assertEqual(len(qs), 1)
  187. qs = SpecialFeature.objects.only("feature__item__name").select_related(
  188. "feature__item"
  189. )
  190. self.assertEqual(len(qs), 1)
  191. def test_defer_annotate_select_related(self):
  192. location = Location.objects.create()
  193. Request.objects.create(location=location)
  194. self.assertIsInstance(
  195. list(
  196. Request.objects.annotate(Count("items"))
  197. .select_related("profile", "location")
  198. .only("profile", "location")
  199. ),
  200. list,
  201. )
  202. self.assertIsInstance(
  203. list(
  204. Request.objects.annotate(Count("items"))
  205. .select_related("profile", "location")
  206. .only("profile__profile1", "location__location1")
  207. ),
  208. list,
  209. )
  210. self.assertIsInstance(
  211. list(
  212. Request.objects.annotate(Count("items"))
  213. .select_related("profile", "location")
  214. .defer("request1", "request2", "request3", "request4")
  215. ),
  216. list,
  217. )
  218. def test_common_model_different_mask(self):
  219. child = Child.objects.create(name="Child", value=42)
  220. second_child = Child.objects.create(name="Second", value=64)
  221. Leaf.objects.create(child=child, second_child=second_child)
  222. with self.assertNumQueries(1):
  223. leaf = (
  224. Leaf.objects.select_related("child", "second_child")
  225. .defer("child__name", "second_child__value")
  226. .get()
  227. )
  228. self.assertEqual(leaf.child, child)
  229. self.assertEqual(leaf.second_child, second_child)
  230. self.assertEqual(leaf.child.get_deferred_fields(), {"name"})
  231. self.assertEqual(leaf.second_child.get_deferred_fields(), {"value"})
  232. with self.assertNumQueries(0):
  233. self.assertEqual(leaf.child.value, 42)
  234. self.assertEqual(leaf.second_child.name, "Second")
  235. with self.assertNumQueries(1):
  236. self.assertEqual(leaf.child.name, "Child")
  237. with self.assertNumQueries(1):
  238. self.assertEqual(leaf.second_child.value, 64)
  239. class DeferDeletionSignalsTests(TestCase):
  240. senders = [Item, Proxy]
  241. @classmethod
  242. def setUpTestData(cls):
  243. cls.item_pk = Item.objects.create(value=1).pk
  244. def setUp(self):
  245. self.pre_delete_senders = []
  246. self.post_delete_senders = []
  247. for sender in self.senders:
  248. models.signals.pre_delete.connect(self.pre_delete_receiver, sender)
  249. models.signals.post_delete.connect(self.post_delete_receiver, sender)
  250. def tearDown(self):
  251. for sender in self.senders:
  252. models.signals.pre_delete.disconnect(self.pre_delete_receiver, sender)
  253. models.signals.post_delete.disconnect(self.post_delete_receiver, sender)
  254. def pre_delete_receiver(self, sender, **kwargs):
  255. self.pre_delete_senders.append(sender)
  256. def post_delete_receiver(self, sender, **kwargs):
  257. self.post_delete_senders.append(sender)
  258. def test_delete_defered_model(self):
  259. Item.objects.only("value").get(pk=self.item_pk).delete()
  260. self.assertEqual(self.pre_delete_senders, [Item])
  261. self.assertEqual(self.post_delete_senders, [Item])
  262. def test_delete_defered_proxy_model(self):
  263. Proxy.objects.only("value").get(pk=self.item_pk).delete()
  264. self.assertEqual(self.pre_delete_senders, [Proxy])
  265. self.assertEqual(self.post_delete_senders, [Proxy])