test_qs_combinators.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. import operator
  2. from django.db import DatabaseError, NotSupportedError, connection
  3. from django.db.models import (
  4. Exists,
  5. F,
  6. IntegerField,
  7. OuterRef,
  8. Subquery,
  9. Transform,
  10. Value,
  11. )
  12. from django.db.models.functions import Mod
  13. from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
  14. from django.test.utils import CaptureQueriesContext
  15. from .models import Author, Celebrity, ExtraInfo, Number, ReservedName
  16. @skipUnlessDBFeature("supports_select_union")
  17. class QuerySetSetOperationTests(TestCase):
  18. @classmethod
  19. def setUpTestData(cls):
  20. Number.objects.bulk_create(Number(num=i, other_num=10 - i) for i in range(10))
  21. def assertNumbersEqual(self, queryset, expected_numbers, ordered=True):
  22. self.assertQuerySetEqual(
  23. queryset, expected_numbers, operator.attrgetter("num"), ordered
  24. )
  25. def test_simple_union(self):
  26. qs1 = Number.objects.filter(num__lte=1)
  27. qs2 = Number.objects.filter(num__gte=8)
  28. qs3 = Number.objects.filter(num=5)
  29. self.assertNumbersEqual(qs1.union(qs2, qs3), [0, 1, 5, 8, 9], ordered=False)
  30. @skipUnlessDBFeature("supports_select_intersection")
  31. def test_simple_intersection(self):
  32. qs1 = Number.objects.filter(num__lte=5)
  33. qs2 = Number.objects.filter(num__gte=5)
  34. qs3 = Number.objects.filter(num__gte=4, num__lte=6)
  35. self.assertNumbersEqual(qs1.intersection(qs2, qs3), [5], ordered=False)
  36. @skipUnlessDBFeature("supports_select_intersection")
  37. def test_intersection_with_values(self):
  38. ReservedName.objects.create(name="a", order=2)
  39. qs1 = ReservedName.objects.all()
  40. reserved_name = qs1.intersection(qs1).values("name", "order", "id").get()
  41. self.assertEqual(reserved_name["name"], "a")
  42. self.assertEqual(reserved_name["order"], 2)
  43. reserved_name = qs1.intersection(qs1).values_list("name", "order", "id").get()
  44. self.assertEqual(reserved_name[:2], ("a", 2))
  45. @skipUnlessDBFeature("supports_select_difference")
  46. def test_simple_difference(self):
  47. qs1 = Number.objects.filter(num__lte=5)
  48. qs2 = Number.objects.filter(num__lte=4)
  49. self.assertNumbersEqual(qs1.difference(qs2), [5], ordered=False)
  50. def test_union_distinct(self):
  51. qs1 = Number.objects.all()
  52. qs2 = Number.objects.all()
  53. self.assertEqual(len(list(qs1.union(qs2, all=True))), 20)
  54. self.assertEqual(len(list(qs1.union(qs2))), 10)
  55. def test_union_none(self):
  56. qs1 = Number.objects.filter(num__lte=1)
  57. qs2 = Number.objects.filter(num__gte=8)
  58. qs3 = qs1.union(qs2)
  59. self.assertSequenceEqual(qs3.none(), [])
  60. self.assertNumbersEqual(qs3, [0, 1, 8, 9], ordered=False)
  61. def test_union_none_slice(self):
  62. qs1 = Number.objects.filter(num__lte=0)
  63. qs2 = Number.objects.none()
  64. qs3 = qs1.union(qs2)
  65. self.assertNumbersEqual(qs3[:1], [0])
  66. def test_union_empty_filter_slice(self):
  67. qs1 = Number.objects.filter(num__lte=0)
  68. qs2 = Number.objects.filter(pk__in=[])
  69. qs3 = qs1.union(qs2)
  70. self.assertNumbersEqual(qs3[:1], [0])
  71. @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
  72. def test_union_slice_compound_empty(self):
  73. qs1 = Number.objects.filter(num__lte=0)[:1]
  74. qs2 = Number.objects.none()
  75. qs3 = qs1.union(qs2)
  76. self.assertNumbersEqual(qs3[:1], [0])
  77. @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
  78. def test_union_combined_slice_compound_empty(self):
  79. qs1 = Number.objects.filter(num__lte=2)[:3]
  80. qs2 = Number.objects.none()
  81. qs3 = qs1.union(qs2)
  82. self.assertNumbersEqual(qs3.order_by("num")[2:3], [2])
  83. def test_union_slice_index(self):
  84. Celebrity.objects.create(name="Famous")
  85. c1 = Celebrity.objects.create(name="Very famous")
  86. qs1 = Celebrity.objects.filter(name="nonexistent")
  87. qs2 = Celebrity.objects.all()
  88. combined_qs = qs1.union(qs2).order_by("name")
  89. self.assertEqual(combined_qs[1], c1)
  90. def test_union_order_with_null_first_last(self):
  91. Number.objects.filter(other_num=5).update(other_num=None)
  92. qs1 = Number.objects.filter(num__lte=1)
  93. qs2 = Number.objects.filter(num__gte=2)
  94. qs3 = qs1.union(qs2)
  95. self.assertSequenceEqual(
  96. qs3.order_by(
  97. F("other_num").asc(nulls_first=True),
  98. ).values_list("other_num", flat=True),
  99. [None, 1, 2, 3, 4, 6, 7, 8, 9, 10],
  100. )
  101. self.assertSequenceEqual(
  102. qs3.order_by(
  103. F("other_num").asc(nulls_last=True),
  104. ).values_list("other_num", flat=True),
  105. [1, 2, 3, 4, 6, 7, 8, 9, 10, None],
  106. )
  107. def test_union_nested(self):
  108. qs1 = Number.objects.all()
  109. qs2 = qs1.union(qs1)
  110. self.assertNumbersEqual(
  111. qs1.union(qs2),
  112. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  113. ordered=False,
  114. )
  115. @skipUnlessDBFeature("supports_select_intersection")
  116. def test_intersection_with_empty_qs(self):
  117. qs1 = Number.objects.all()
  118. qs2 = Number.objects.none()
  119. qs3 = Number.objects.filter(pk__in=[])
  120. self.assertEqual(len(qs1.intersection(qs2)), 0)
  121. self.assertEqual(len(qs1.intersection(qs3)), 0)
  122. self.assertEqual(len(qs2.intersection(qs1)), 0)
  123. self.assertEqual(len(qs3.intersection(qs1)), 0)
  124. self.assertEqual(len(qs2.intersection(qs2)), 0)
  125. self.assertEqual(len(qs3.intersection(qs3)), 0)
  126. @skipUnlessDBFeature("supports_select_difference")
  127. def test_difference_with_empty_qs(self):
  128. qs1 = Number.objects.all()
  129. qs2 = Number.objects.none()
  130. qs3 = Number.objects.filter(pk__in=[])
  131. self.assertEqual(len(qs1.difference(qs2)), 10)
  132. self.assertEqual(len(qs1.difference(qs3)), 10)
  133. self.assertEqual(len(qs2.difference(qs1)), 0)
  134. self.assertEqual(len(qs3.difference(qs1)), 0)
  135. self.assertEqual(len(qs2.difference(qs2)), 0)
  136. self.assertEqual(len(qs3.difference(qs3)), 0)
  137. @skipUnlessDBFeature("supports_select_difference")
  138. def test_difference_with_values(self):
  139. ReservedName.objects.create(name="a", order=2)
  140. qs1 = ReservedName.objects.all()
  141. qs2 = ReservedName.objects.none()
  142. reserved_name = qs1.difference(qs2).values("name", "order", "id").get()
  143. self.assertEqual(reserved_name["name"], "a")
  144. self.assertEqual(reserved_name["order"], 2)
  145. reserved_name = qs1.difference(qs2).values_list("name", "order", "id").get()
  146. self.assertEqual(reserved_name[:2], ("a", 2))
  147. def test_union_with_empty_qs(self):
  148. qs1 = Number.objects.all()
  149. qs2 = Number.objects.none()
  150. qs3 = Number.objects.filter(pk__in=[])
  151. self.assertEqual(len(qs1.union(qs2)), 10)
  152. self.assertEqual(len(qs2.union(qs1)), 10)
  153. self.assertEqual(len(qs1.union(qs3)), 10)
  154. self.assertEqual(len(qs3.union(qs1)), 10)
  155. self.assertEqual(len(qs2.union(qs1, qs1, qs1)), 10)
  156. self.assertEqual(len(qs2.union(qs1, qs1, all=True)), 20)
  157. self.assertEqual(len(qs2.union(qs2)), 0)
  158. self.assertEqual(len(qs3.union(qs3)), 0)
  159. def test_empty_qs_union_with_ordered_qs(self):
  160. qs1 = Number.objects.order_by("num")
  161. qs2 = Number.objects.none().union(qs1).order_by("num")
  162. self.assertEqual(list(qs1), list(qs2))
  163. def test_limits(self):
  164. qs1 = Number.objects.all()
  165. qs2 = Number.objects.all()
  166. self.assertEqual(len(list(qs1.union(qs2)[:2])), 2)
  167. def test_ordering(self):
  168. qs1 = Number.objects.filter(num__lte=1)
  169. qs2 = Number.objects.filter(num__gte=2, num__lte=3)
  170. self.assertNumbersEqual(qs1.union(qs2).order_by("-num"), [3, 2, 1, 0])
  171. def test_ordering_by_alias(self):
  172. qs1 = Number.objects.filter(num__lte=1).values(alias=F("num"))
  173. qs2 = Number.objects.filter(num__gte=2, num__lte=3).values(alias=F("num"))
  174. self.assertQuerySetEqual(
  175. qs1.union(qs2).order_by("-alias"),
  176. [3, 2, 1, 0],
  177. operator.itemgetter("alias"),
  178. )
  179. def test_ordering_by_f_expression(self):
  180. qs1 = Number.objects.filter(num__lte=1)
  181. qs2 = Number.objects.filter(num__gte=2, num__lte=3)
  182. self.assertNumbersEqual(qs1.union(qs2).order_by(F("num").desc()), [3, 2, 1, 0])
  183. def test_ordering_by_f_expression_and_alias(self):
  184. qs1 = Number.objects.filter(num__lte=1).values(alias=F("other_num"))
  185. qs2 = Number.objects.filter(num__gte=2, num__lte=3).values(alias=F("other_num"))
  186. self.assertQuerySetEqual(
  187. qs1.union(qs2).order_by(F("alias").desc()),
  188. [10, 9, 8, 7],
  189. operator.itemgetter("alias"),
  190. )
  191. Number.objects.create(num=-1)
  192. self.assertQuerySetEqual(
  193. qs1.union(qs2).order_by(F("alias").desc(nulls_last=True)),
  194. [10, 9, 8, 7, None],
  195. operator.itemgetter("alias"),
  196. )
  197. def test_union_with_values(self):
  198. ReservedName.objects.create(name="a", order=2)
  199. qs1 = ReservedName.objects.all()
  200. reserved_name = qs1.union(qs1).values("name", "order", "id").get()
  201. self.assertEqual(reserved_name["name"], "a")
  202. self.assertEqual(reserved_name["order"], 2)
  203. reserved_name = qs1.union(qs1).values_list("name", "order", "id").get()
  204. self.assertEqual(reserved_name[:2], ("a", 2))
  205. # List of columns can be changed.
  206. reserved_name = qs1.union(qs1).values_list("order").get()
  207. self.assertEqual(reserved_name, (2,))
  208. def test_union_with_two_annotated_values_list(self):
  209. qs1 = (
  210. Number.objects.filter(num=1)
  211. .annotate(
  212. count=Value(0, IntegerField()),
  213. )
  214. .values_list("num", "count")
  215. )
  216. qs2 = (
  217. Number.objects.filter(num=2)
  218. .values("pk")
  219. .annotate(
  220. count=F("num"),
  221. )
  222. .annotate(
  223. num=Value(1, IntegerField()),
  224. )
  225. .values_list("num", "count")
  226. )
  227. self.assertCountEqual(qs1.union(qs2), [(1, 0), (1, 2)])
  228. def test_union_with_field_and_annotation_values(self):
  229. qs1 = (
  230. Number.objects.filter(num=1)
  231. .annotate(
  232. zero=Value(0, IntegerField()),
  233. )
  234. .values_list("num", "zero")
  235. )
  236. qs2 = (
  237. Number.objects.filter(num=2)
  238. .annotate(
  239. zero=Value(0, IntegerField()),
  240. )
  241. .values_list("zero", "num")
  242. )
  243. self.assertCountEqual(qs1.union(qs2), [(1, 0), (0, 2)])
  244. def test_union_with_extra_and_values_list(self):
  245. qs1 = (
  246. Number.objects.filter(num=1)
  247. .extra(
  248. select={"count": 0},
  249. )
  250. .values_list("num", "count")
  251. )
  252. qs2 = (
  253. Number.objects.filter(num=2)
  254. .extra(select={"count": 1})
  255. .values_list("num", "count")
  256. )
  257. self.assertCountEqual(qs1.union(qs2), [(1, 0), (2, 1)])
  258. def test_union_with_values_list_on_annotated_and_unannotated(self):
  259. ReservedName.objects.create(name="rn1", order=1)
  260. qs1 = Number.objects.annotate(
  261. has_reserved_name=Exists(ReservedName.objects.filter(order=OuterRef("num")))
  262. ).filter(has_reserved_name=True)
  263. qs2 = Number.objects.filter(num=9)
  264. self.assertCountEqual(qs1.union(qs2).values_list("num", flat=True), [1, 9])
  265. def test_union_with_values_list_and_order(self):
  266. ReservedName.objects.bulk_create(
  267. [
  268. ReservedName(name="rn1", order=7),
  269. ReservedName(name="rn2", order=5),
  270. ReservedName(name="rn0", order=6),
  271. ReservedName(name="rn9", order=-1),
  272. ]
  273. )
  274. qs1 = ReservedName.objects.filter(order__gte=6)
  275. qs2 = ReservedName.objects.filter(order__lte=5)
  276. union_qs = qs1.union(qs2)
  277. for qs, expected_result in (
  278. # Order by a single column.
  279. (union_qs.order_by("-pk").values_list("order", flat=True), [-1, 6, 5, 7]),
  280. (union_qs.order_by("pk").values_list("order", flat=True), [7, 5, 6, -1]),
  281. (union_qs.values_list("order", flat=True).order_by("-pk"), [-1, 6, 5, 7]),
  282. (union_qs.values_list("order", flat=True).order_by("pk"), [7, 5, 6, -1]),
  283. # Order by multiple columns.
  284. (
  285. union_qs.order_by("-name", "pk").values_list("order", flat=True),
  286. [-1, 5, 7, 6],
  287. ),
  288. (
  289. union_qs.values_list("order", flat=True).order_by("-name", "pk"),
  290. [-1, 5, 7, 6],
  291. ),
  292. ):
  293. with self.subTest(qs=qs):
  294. self.assertEqual(list(qs), expected_result)
  295. def test_union_with_values_list_and_order_on_annotation(self):
  296. qs1 = Number.objects.annotate(
  297. annotation=Value(-1),
  298. multiplier=F("annotation"),
  299. ).filter(num__gte=6)
  300. qs2 = Number.objects.annotate(
  301. annotation=Value(2),
  302. multiplier=F("annotation"),
  303. ).filter(num__lte=5)
  304. self.assertSequenceEqual(
  305. qs1.union(qs2).order_by("annotation", "num").values_list("num", flat=True),
  306. [6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
  307. )
  308. self.assertQuerySetEqual(
  309. qs1.union(qs2)
  310. .order_by(
  311. F("annotation") * F("multiplier"),
  312. "num",
  313. )
  314. .values("num"),
  315. [6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
  316. operator.itemgetter("num"),
  317. )
  318. def test_order_by_annotation_transform(self):
  319. class Mod2(Mod, Transform):
  320. def __init__(self, expr):
  321. super().__init__(expr, 2)
  322. output_field = IntegerField()
  323. output_field.register_lookup(Mod2, "mod2")
  324. qs1 = Number.objects.annotate(
  325. annotation=Value(1, output_field=output_field),
  326. )
  327. qs2 = Number.objects.annotate(
  328. annotation=Value(2, output_field=output_field),
  329. )
  330. msg = "Ordering combined queries by transforms is not implemented."
  331. with self.assertRaisesMessage(NotImplementedError, msg):
  332. list(qs1.union(qs2).order_by("annotation__mod2"))
  333. def test_union_with_select_related_and_order(self):
  334. e1 = ExtraInfo.objects.create(value=7, info="e1")
  335. a1 = Author.objects.create(name="a1", num=1, extra=e1)
  336. a2 = Author.objects.create(name="a2", num=3, extra=e1)
  337. Author.objects.create(name="a3", num=2, extra=e1)
  338. base_qs = Author.objects.select_related("extra").order_by()
  339. qs1 = base_qs.filter(name="a1")
  340. qs2 = base_qs.filter(name="a2")
  341. self.assertSequenceEqual(qs1.union(qs2).order_by("pk"), [a1, a2])
  342. @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
  343. def test_union_with_select_related_and_first(self):
  344. e1 = ExtraInfo.objects.create(value=7, info="e1")
  345. a1 = Author.objects.create(name="a1", num=1, extra=e1)
  346. Author.objects.create(name="a2", num=3, extra=e1)
  347. base_qs = Author.objects.select_related("extra").order_by()
  348. qs1 = base_qs.filter(name="a1")
  349. qs2 = base_qs.filter(name="a2")
  350. self.assertEqual(qs1.union(qs2).order_by("name").first(), a1)
  351. def test_union_with_first(self):
  352. e1 = ExtraInfo.objects.create(value=7, info="e1")
  353. a1 = Author.objects.create(name="a1", num=1, extra=e1)
  354. base_qs = Author.objects.order_by()
  355. qs1 = base_qs.filter(name="a1")
  356. qs2 = base_qs.filter(name="a2")
  357. self.assertEqual(qs1.union(qs2).first(), a1)
  358. def test_union_multiple_models_with_values_list_and_order(self):
  359. reserved_name = ReservedName.objects.create(name="rn1", order=0)
  360. qs1 = Celebrity.objects.all()
  361. qs2 = ReservedName.objects.all()
  362. self.assertSequenceEqual(
  363. qs1.union(qs2).order_by("name").values_list("pk", flat=True),
  364. [reserved_name.pk],
  365. )
  366. def test_union_multiple_models_with_values_list_and_order_by_extra_select(self):
  367. reserved_name = ReservedName.objects.create(name="rn1", order=0)
  368. qs1 = Celebrity.objects.extra(select={"extra_name": "name"})
  369. qs2 = ReservedName.objects.extra(select={"extra_name": "name"})
  370. self.assertSequenceEqual(
  371. qs1.union(qs2).order_by("extra_name").values_list("pk", flat=True),
  372. [reserved_name.pk],
  373. )
  374. def test_union_multiple_models_with_values_list_and_annotations(self):
  375. ReservedName.objects.create(name="rn1", order=10)
  376. Celebrity.objects.create(name="c1")
  377. qs1 = ReservedName.objects.annotate(row_type=Value("rn")).values_list(
  378. "name", "order", "row_type"
  379. )
  380. qs2 = Celebrity.objects.annotate(
  381. row_type=Value("cb"), order=Value(-10)
  382. ).values_list("name", "order", "row_type")
  383. self.assertSequenceEqual(
  384. qs1.union(qs2).order_by("order"),
  385. [("c1", -10, "cb"), ("rn1", 10, "rn")],
  386. )
  387. def test_union_in_subquery(self):
  388. ReservedName.objects.bulk_create(
  389. [
  390. ReservedName(name="rn1", order=8),
  391. ReservedName(name="rn2", order=1),
  392. ReservedName(name="rn3", order=5),
  393. ]
  394. )
  395. qs1 = Number.objects.filter(num__gt=7, num=OuterRef("order"))
  396. qs2 = Number.objects.filter(num__lt=2, num=OuterRef("order"))
  397. self.assertCountEqual(
  398. ReservedName.objects.annotate(
  399. number=Subquery(qs1.union(qs2).values("num")),
  400. )
  401. .filter(number__isnull=False)
  402. .values_list("order", flat=True),
  403. [8, 1],
  404. )
  405. def test_union_in_subquery_related_outerref(self):
  406. e1 = ExtraInfo.objects.create(value=7, info="e3")
  407. e2 = ExtraInfo.objects.create(value=5, info="e2")
  408. e3 = ExtraInfo.objects.create(value=1, info="e1")
  409. Author.objects.bulk_create(
  410. [
  411. Author(name="a1", num=1, extra=e1),
  412. Author(name="a2", num=3, extra=e2),
  413. Author(name="a3", num=2, extra=e3),
  414. ]
  415. )
  416. qs1 = ExtraInfo.objects.order_by().filter(value=OuterRef("num"))
  417. qs2 = ExtraInfo.objects.order_by().filter(value__lt=OuterRef("extra__value"))
  418. qs = (
  419. Author.objects.annotate(
  420. info=Subquery(qs1.union(qs2).values("info")[:1]),
  421. )
  422. .filter(info__isnull=False)
  423. .values_list("name", flat=True)
  424. )
  425. self.assertCountEqual(qs, ["a1", "a2"])
  426. # Combined queries don't mutate.
  427. self.assertCountEqual(qs, ["a1", "a2"])
  428. @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
  429. def test_union_in_with_ordering(self):
  430. qs1 = Number.objects.filter(num__gt=7).order_by("num")
  431. qs2 = Number.objects.filter(num__lt=2).order_by("num")
  432. self.assertNumbersEqual(
  433. Number.objects.exclude(id__in=qs1.union(qs2).values("id")),
  434. [2, 3, 4, 5, 6, 7],
  435. ordered=False,
  436. )
  437. @skipUnlessDBFeature(
  438. "supports_slicing_ordering_in_compound", "allow_sliced_subqueries_with_in"
  439. )
  440. def test_union_in_with_ordering_and_slice(self):
  441. qs1 = Number.objects.filter(num__gt=7).order_by("num")[:1]
  442. qs2 = Number.objects.filter(num__lt=2).order_by("-num")[:1]
  443. self.assertNumbersEqual(
  444. Number.objects.exclude(id__in=qs1.union(qs2).values("id")),
  445. [0, 2, 3, 4, 5, 6, 7, 9],
  446. ordered=False,
  447. )
  448. def test_count_union(self):
  449. qs1 = Number.objects.filter(num__lte=1).values("num")
  450. qs2 = Number.objects.filter(num__gte=2, num__lte=3).values("num")
  451. self.assertEqual(qs1.union(qs2).count(), 4)
  452. def test_count_union_empty_result(self):
  453. qs = Number.objects.filter(pk__in=[])
  454. self.assertEqual(qs.union(qs).count(), 0)
  455. def test_count_union_with_select_related(self):
  456. e1 = ExtraInfo.objects.create(value=1, info="e1")
  457. Author.objects.create(name="a1", num=1, extra=e1)
  458. qs = Author.objects.select_related("extra").order_by()
  459. self.assertEqual(qs.union(qs).count(), 1)
  460. @skipUnlessDBFeature("supports_select_difference")
  461. def test_count_difference(self):
  462. qs1 = Number.objects.filter(num__lt=10)
  463. qs2 = Number.objects.filter(num__lt=9)
  464. self.assertEqual(qs1.difference(qs2).count(), 1)
  465. @skipUnlessDBFeature("supports_select_intersection")
  466. def test_count_intersection(self):
  467. qs1 = Number.objects.filter(num__gte=5)
  468. qs2 = Number.objects.filter(num__lte=5)
  469. self.assertEqual(qs1.intersection(qs2).count(), 1)
  470. def test_exists_union(self):
  471. qs1 = Number.objects.filter(num__gte=5)
  472. qs2 = Number.objects.filter(num__lte=5)
  473. with CaptureQueriesContext(connection) as context:
  474. self.assertIs(qs1.union(qs2).exists(), True)
  475. captured_queries = context.captured_queries
  476. self.assertEqual(len(captured_queries), 1)
  477. captured_sql = captured_queries[0]["sql"]
  478. self.assertNotIn(
  479. connection.ops.quote_name(Number._meta.pk.column),
  480. captured_sql,
  481. )
  482. self.assertEqual(
  483. captured_sql.count(connection.ops.limit_offset_sql(None, 1)), 1
  484. )
  485. def test_exists_union_empty_result(self):
  486. qs = Number.objects.filter(pk__in=[])
  487. self.assertIs(qs.union(qs).exists(), False)
  488. @skipUnlessDBFeature("supports_select_intersection")
  489. def test_exists_intersection(self):
  490. qs1 = Number.objects.filter(num__gt=5)
  491. qs2 = Number.objects.filter(num__lt=5)
  492. self.assertIs(qs1.intersection(qs1).exists(), True)
  493. self.assertIs(qs1.intersection(qs2).exists(), False)
  494. @skipUnlessDBFeature("supports_select_difference")
  495. def test_exists_difference(self):
  496. qs1 = Number.objects.filter(num__gte=5)
  497. qs2 = Number.objects.filter(num__gte=3)
  498. self.assertIs(qs1.difference(qs2).exists(), False)
  499. self.assertIs(qs2.difference(qs1).exists(), True)
  500. def test_get_union(self):
  501. qs = Number.objects.filter(num=2)
  502. self.assertEqual(qs.union(qs).get().num, 2)
  503. @skipUnlessDBFeature("supports_select_difference")
  504. def test_get_difference(self):
  505. qs1 = Number.objects.all()
  506. qs2 = Number.objects.exclude(num=2)
  507. self.assertEqual(qs1.difference(qs2).get().num, 2)
  508. @skipUnlessDBFeature("supports_select_intersection")
  509. def test_get_intersection(self):
  510. qs1 = Number.objects.all()
  511. qs2 = Number.objects.filter(num=2)
  512. self.assertEqual(qs1.intersection(qs2).get().num, 2)
  513. @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
  514. def test_ordering_subqueries(self):
  515. qs1 = Number.objects.order_by("num")[:2]
  516. qs2 = Number.objects.order_by("-num")[:2]
  517. self.assertNumbersEqual(qs1.union(qs2).order_by("-num")[:4], [9, 8, 1, 0])
  518. @skipIfDBFeature("supports_slicing_ordering_in_compound")
  519. def test_unsupported_ordering_slicing_raises_db_error(self):
  520. qs1 = Number.objects.all()
  521. qs2 = Number.objects.all()
  522. qs3 = Number.objects.all()
  523. msg = "LIMIT/OFFSET not allowed in subqueries of compound statements"
  524. with self.assertRaisesMessage(DatabaseError, msg):
  525. list(qs1.union(qs2[:10]))
  526. msg = "ORDER BY not allowed in subqueries of compound statements"
  527. with self.assertRaisesMessage(DatabaseError, msg):
  528. list(qs1.order_by("id").union(qs2))
  529. with self.assertRaisesMessage(DatabaseError, msg):
  530. list(qs1.union(qs2).order_by("id").union(qs3))
  531. @skipIfDBFeature("supports_select_intersection")
  532. def test_unsupported_intersection_raises_db_error(self):
  533. qs1 = Number.objects.all()
  534. qs2 = Number.objects.all()
  535. msg = "intersection is not supported on this database backend"
  536. with self.assertRaisesMessage(NotSupportedError, msg):
  537. list(qs1.intersection(qs2))
  538. def test_combining_multiple_models(self):
  539. ReservedName.objects.create(name="99 little bugs", order=99)
  540. qs1 = Number.objects.filter(num=1).values_list("num", flat=True)
  541. qs2 = ReservedName.objects.values_list("order")
  542. self.assertEqual(list(qs1.union(qs2).order_by("num")), [1, 99])
  543. def test_order_raises_on_non_selected_column(self):
  544. qs1 = (
  545. Number.objects.filter()
  546. .annotate(
  547. annotation=Value(1, IntegerField()),
  548. )
  549. .values("annotation", num2=F("num"))
  550. )
  551. qs2 = Number.objects.filter().values("id", "num")
  552. # Should not raise
  553. list(qs1.union(qs2).order_by("annotation"))
  554. list(qs1.union(qs2).order_by("num2"))
  555. msg = "ORDER BY term does not match any column in the result set"
  556. # 'id' is not part of the select
  557. with self.assertRaisesMessage(DatabaseError, msg):
  558. list(qs1.union(qs2).order_by("id"))
  559. # 'num' got realiased to num2
  560. with self.assertRaisesMessage(DatabaseError, msg):
  561. list(qs1.union(qs2).order_by("num"))
  562. with self.assertRaisesMessage(DatabaseError, msg):
  563. list(qs1.union(qs2).order_by(F("num")))
  564. with self.assertRaisesMessage(DatabaseError, msg):
  565. list(qs1.union(qs2).order_by(F("num").desc()))
  566. # switched order, now 'exists' again:
  567. list(qs2.union(qs1).order_by("num"))
  568. @skipUnlessDBFeature("supports_select_difference", "supports_select_intersection")
  569. def test_qs_with_subcompound_qs(self):
  570. qs1 = Number.objects.all()
  571. qs2 = Number.objects.intersection(Number.objects.filter(num__gt=1))
  572. self.assertEqual(qs1.difference(qs2).count(), 2)
  573. def test_order_by_same_type(self):
  574. qs = Number.objects.all()
  575. union = qs.union(qs)
  576. numbers = list(range(10))
  577. self.assertNumbersEqual(union.order_by("num"), numbers)
  578. self.assertNumbersEqual(union.order_by("other_num"), reversed(numbers))
  579. def test_unsupported_operations_on_combined_qs(self):
  580. qs = Number.objects.all()
  581. msg = "Calling QuerySet.%s() after %s() is not supported."
  582. combinators = ["union"]
  583. if connection.features.supports_select_difference:
  584. combinators.append("difference")
  585. if connection.features.supports_select_intersection:
  586. combinators.append("intersection")
  587. for combinator in combinators:
  588. for operation in (
  589. "alias",
  590. "annotate",
  591. "defer",
  592. "delete",
  593. "distinct",
  594. "exclude",
  595. "extra",
  596. "filter",
  597. "only",
  598. "prefetch_related",
  599. "select_related",
  600. "update",
  601. ):
  602. with self.subTest(combinator=combinator, operation=operation):
  603. with self.assertRaisesMessage(
  604. NotSupportedError,
  605. msg % (operation, combinator),
  606. ):
  607. getattr(getattr(qs, combinator)(qs), operation)()
  608. with self.assertRaisesMessage(
  609. NotSupportedError,
  610. msg % ("contains", combinator),
  611. ):
  612. obj = Number.objects.first()
  613. getattr(qs, combinator)(qs).contains(obj)
  614. def test_get_with_filters_unsupported_on_combined_qs(self):
  615. qs = Number.objects.all()
  616. msg = "Calling QuerySet.get(...) with filters after %s() is not supported."
  617. combinators = ["union"]
  618. if connection.features.supports_select_difference:
  619. combinators.append("difference")
  620. if connection.features.supports_select_intersection:
  621. combinators.append("intersection")
  622. for combinator in combinators:
  623. with self.subTest(combinator=combinator):
  624. with self.assertRaisesMessage(NotSupportedError, msg % combinator):
  625. getattr(qs, combinator)(qs).get(num=2)
  626. def test_operator_on_combined_qs_error(self):
  627. qs = Number.objects.all()
  628. msg = "Cannot use %s operator with combined queryset."
  629. combinators = ["union"]
  630. if connection.features.supports_select_difference:
  631. combinators.append("difference")
  632. if connection.features.supports_select_intersection:
  633. combinators.append("intersection")
  634. operators = [
  635. ("|", operator.or_),
  636. ("&", operator.and_),
  637. ("^", operator.xor),
  638. ]
  639. for combinator in combinators:
  640. combined_qs = getattr(qs, combinator)(qs)
  641. for operator_, operator_func in operators:
  642. with self.subTest(combinator=combinator):
  643. with self.assertRaisesMessage(TypeError, msg % operator_):
  644. operator_func(qs, combined_qs)
  645. with self.assertRaisesMessage(TypeError, msg % operator_):
  646. operator_func(combined_qs, qs)