tests.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. from datetime import datetime
  2. from operator import attrgetter
  3. from django.db.models import (
  4. CharField,
  5. Count,
  6. DateTimeField,
  7. F,
  8. Max,
  9. OuterRef,
  10. Subquery,
  11. Value,
  12. )
  13. from django.db.models.functions import Upper
  14. from django.test import TestCase
  15. from .models import (
  16. Article,
  17. Author,
  18. ChildArticle,
  19. OrderedByExpression,
  20. OrderedByExpressionChild,
  21. OrderedByExpressionGrandChild,
  22. OrderedByFArticle,
  23. Reference,
  24. )
  25. class OrderingTests(TestCase):
  26. @classmethod
  27. def setUpTestData(cls):
  28. cls.a1 = Article.objects.create(
  29. headline="Article 1", pub_date=datetime(2005, 7, 26)
  30. )
  31. cls.a2 = Article.objects.create(
  32. headline="Article 2", pub_date=datetime(2005, 7, 27)
  33. )
  34. cls.a3 = Article.objects.create(
  35. headline="Article 3", pub_date=datetime(2005, 7, 27)
  36. )
  37. cls.a4 = Article.objects.create(
  38. headline="Article 4", pub_date=datetime(2005, 7, 28)
  39. )
  40. cls.author_1 = Author.objects.create(name="Name 1")
  41. cls.author_2 = Author.objects.create(name="Name 2")
  42. for i in range(2):
  43. Author.objects.create()
  44. def test_default_ordering(self):
  45. """
  46. By default, Article.objects.all() orders by pub_date descending, then
  47. headline ascending.
  48. """
  49. self.assertQuerysetEqual(
  50. Article.objects.all(),
  51. [
  52. "Article 4",
  53. "Article 2",
  54. "Article 3",
  55. "Article 1",
  56. ],
  57. attrgetter("headline"),
  58. )
  59. # Getting a single item should work too:
  60. self.assertEqual(Article.objects.all()[0], self.a4)
  61. def test_default_ordering_override(self):
  62. """
  63. Override ordering with order_by, which is in the same format as the
  64. ordering attribute in models.
  65. """
  66. self.assertQuerysetEqual(
  67. Article.objects.order_by("headline"),
  68. [
  69. "Article 1",
  70. "Article 2",
  71. "Article 3",
  72. "Article 4",
  73. ],
  74. attrgetter("headline"),
  75. )
  76. self.assertQuerysetEqual(
  77. Article.objects.order_by("pub_date", "-headline"),
  78. [
  79. "Article 1",
  80. "Article 3",
  81. "Article 2",
  82. "Article 4",
  83. ],
  84. attrgetter("headline"),
  85. )
  86. def test_order_by_override(self):
  87. """
  88. Only the last order_by has any effect (since they each override any
  89. previous ordering).
  90. """
  91. self.assertQuerysetEqual(
  92. Article.objects.order_by("id"),
  93. [
  94. "Article 1",
  95. "Article 2",
  96. "Article 3",
  97. "Article 4",
  98. ],
  99. attrgetter("headline"),
  100. )
  101. self.assertQuerysetEqual(
  102. Article.objects.order_by("id").order_by("-headline"),
  103. [
  104. "Article 4",
  105. "Article 3",
  106. "Article 2",
  107. "Article 1",
  108. ],
  109. attrgetter("headline"),
  110. )
  111. def test_order_by_nulls_first_and_last(self):
  112. msg = "nulls_first and nulls_last are mutually exclusive"
  113. with self.assertRaisesMessage(ValueError, msg):
  114. Article.objects.order_by(
  115. F("author").desc(nulls_last=True, nulls_first=True)
  116. )
  117. def assertQuerysetEqualReversible(self, queryset, sequence):
  118. self.assertSequenceEqual(queryset, sequence)
  119. self.assertSequenceEqual(queryset.reverse(), list(reversed(sequence)))
  120. def test_order_by_nulls_last(self):
  121. Article.objects.filter(headline="Article 3").update(author=self.author_1)
  122. Article.objects.filter(headline="Article 4").update(author=self.author_2)
  123. # asc and desc are chainable with nulls_last.
  124. self.assertQuerysetEqualReversible(
  125. Article.objects.order_by(F("author").desc(nulls_last=True), "headline"),
  126. [self.a4, self.a3, self.a1, self.a2],
  127. )
  128. self.assertQuerysetEqualReversible(
  129. Article.objects.order_by(F("author").asc(nulls_last=True), "headline"),
  130. [self.a3, self.a4, self.a1, self.a2],
  131. )
  132. self.assertQuerysetEqualReversible(
  133. Article.objects.order_by(
  134. Upper("author__name").desc(nulls_last=True), "headline"
  135. ),
  136. [self.a4, self.a3, self.a1, self.a2],
  137. )
  138. self.assertQuerysetEqualReversible(
  139. Article.objects.order_by(
  140. Upper("author__name").asc(nulls_last=True), "headline"
  141. ),
  142. [self.a3, self.a4, self.a1, self.a2],
  143. )
  144. def test_order_by_nulls_first(self):
  145. Article.objects.filter(headline="Article 3").update(author=self.author_1)
  146. Article.objects.filter(headline="Article 4").update(author=self.author_2)
  147. # asc and desc are chainable with nulls_first.
  148. self.assertQuerysetEqualReversible(
  149. Article.objects.order_by(F("author").asc(nulls_first=True), "headline"),
  150. [self.a1, self.a2, self.a3, self.a4],
  151. )
  152. self.assertQuerysetEqualReversible(
  153. Article.objects.order_by(F("author").desc(nulls_first=True), "headline"),
  154. [self.a1, self.a2, self.a4, self.a3],
  155. )
  156. self.assertQuerysetEqualReversible(
  157. Article.objects.order_by(
  158. Upper("author__name").asc(nulls_first=True), "headline"
  159. ),
  160. [self.a1, self.a2, self.a3, self.a4],
  161. )
  162. self.assertQuerysetEqualReversible(
  163. Article.objects.order_by(
  164. Upper("author__name").desc(nulls_first=True), "headline"
  165. ),
  166. [self.a1, self.a2, self.a4, self.a3],
  167. )
  168. def test_orders_nulls_first_on_filtered_subquery(self):
  169. Article.objects.filter(headline="Article 1").update(author=self.author_1)
  170. Article.objects.filter(headline="Article 2").update(author=self.author_1)
  171. Article.objects.filter(headline="Article 4").update(author=self.author_2)
  172. Author.objects.filter(name__isnull=True).delete()
  173. author_3 = Author.objects.create(name="Name 3")
  174. article_subquery = (
  175. Article.objects.filter(
  176. author=OuterRef("pk"),
  177. headline__icontains="Article",
  178. )
  179. .order_by()
  180. .values("author")
  181. .annotate(
  182. last_date=Max("pub_date"),
  183. )
  184. .values("last_date")
  185. )
  186. self.assertQuerysetEqualReversible(
  187. Author.objects.annotate(
  188. last_date=Subquery(article_subquery, output_field=DateTimeField())
  189. )
  190. .order_by(F("last_date").asc(nulls_first=True))
  191. .distinct(),
  192. [author_3, self.author_1, self.author_2],
  193. )
  194. def test_stop_slicing(self):
  195. """
  196. Use the 'stop' part of slicing notation to limit the results.
  197. """
  198. self.assertQuerysetEqual(
  199. Article.objects.order_by("headline")[:2],
  200. [
  201. "Article 1",
  202. "Article 2",
  203. ],
  204. attrgetter("headline"),
  205. )
  206. def test_stop_start_slicing(self):
  207. """
  208. Use the 'stop' and 'start' parts of slicing notation to offset the
  209. result list.
  210. """
  211. self.assertQuerysetEqual(
  212. Article.objects.order_by("headline")[1:3],
  213. [
  214. "Article 2",
  215. "Article 3",
  216. ],
  217. attrgetter("headline"),
  218. )
  219. def test_random_ordering(self):
  220. """
  221. Use '?' to order randomly.
  222. """
  223. self.assertEqual(len(list(Article.objects.order_by("?"))), 4)
  224. def test_reversed_ordering(self):
  225. """
  226. Ordering can be reversed using the reverse() method on a queryset.
  227. This allows you to extract things like "the last two items" (reverse
  228. and then take the first two).
  229. """
  230. self.assertQuerysetEqual(
  231. Article.objects.reverse()[:2],
  232. [
  233. "Article 1",
  234. "Article 3",
  235. ],
  236. attrgetter("headline"),
  237. )
  238. def test_reverse_ordering_pure(self):
  239. qs1 = Article.objects.order_by(F("headline").asc())
  240. qs2 = qs1.reverse()
  241. self.assertQuerysetEqual(
  242. qs2,
  243. [
  244. "Article 4",
  245. "Article 3",
  246. "Article 2",
  247. "Article 1",
  248. ],
  249. attrgetter("headline"),
  250. )
  251. self.assertQuerysetEqual(
  252. qs1,
  253. [
  254. "Article 1",
  255. "Article 2",
  256. "Article 3",
  257. "Article 4",
  258. ],
  259. attrgetter("headline"),
  260. )
  261. def test_reverse_meta_ordering_pure(self):
  262. Article.objects.create(
  263. headline="Article 5",
  264. pub_date=datetime(2005, 7, 30),
  265. author=self.author_1,
  266. second_author=self.author_2,
  267. )
  268. Article.objects.create(
  269. headline="Article 5",
  270. pub_date=datetime(2005, 7, 30),
  271. author=self.author_2,
  272. second_author=self.author_1,
  273. )
  274. self.assertQuerysetEqual(
  275. Article.objects.filter(headline="Article 5").reverse(),
  276. ["Name 2", "Name 1"],
  277. attrgetter("author.name"),
  278. )
  279. self.assertQuerysetEqual(
  280. Article.objects.filter(headline="Article 5"),
  281. ["Name 1", "Name 2"],
  282. attrgetter("author.name"),
  283. )
  284. def test_no_reordering_after_slicing(self):
  285. msg = "Cannot reverse a query once a slice has been taken."
  286. qs = Article.objects.all()[0:2]
  287. with self.assertRaisesMessage(TypeError, msg):
  288. qs.reverse()
  289. with self.assertRaisesMessage(TypeError, msg):
  290. qs.last()
  291. def test_extra_ordering(self):
  292. """
  293. Ordering can be based on fields included from an 'extra' clause
  294. """
  295. self.assertQuerysetEqual(
  296. Article.objects.extra(
  297. select={"foo": "pub_date"}, order_by=["foo", "headline"]
  298. ),
  299. [
  300. "Article 1",
  301. "Article 2",
  302. "Article 3",
  303. "Article 4",
  304. ],
  305. attrgetter("headline"),
  306. )
  307. def test_extra_ordering_quoting(self):
  308. """
  309. If the extra clause uses an SQL keyword for a name, it will be
  310. protected by quoting.
  311. """
  312. self.assertQuerysetEqual(
  313. Article.objects.extra(
  314. select={"order": "pub_date"}, order_by=["order", "headline"]
  315. ),
  316. [
  317. "Article 1",
  318. "Article 2",
  319. "Article 3",
  320. "Article 4",
  321. ],
  322. attrgetter("headline"),
  323. )
  324. def test_extra_ordering_with_table_name(self):
  325. self.assertQuerysetEqual(
  326. Article.objects.extra(order_by=["ordering_article.headline"]),
  327. [
  328. "Article 1",
  329. "Article 2",
  330. "Article 3",
  331. "Article 4",
  332. ],
  333. attrgetter("headline"),
  334. )
  335. self.assertQuerysetEqual(
  336. Article.objects.extra(order_by=["-ordering_article.headline"]),
  337. [
  338. "Article 4",
  339. "Article 3",
  340. "Article 2",
  341. "Article 1",
  342. ],
  343. attrgetter("headline"),
  344. )
  345. def test_order_by_pk(self):
  346. """
  347. 'pk' works as an ordering option in Meta.
  348. """
  349. self.assertEqual(
  350. [a.pk for a in Author.objects.all()],
  351. [a.pk for a in Author.objects.order_by("-pk")],
  352. )
  353. def test_order_by_fk_attname(self):
  354. """
  355. ordering by a foreign key by its attribute name prevents the query
  356. from inheriting its related model ordering option (#19195).
  357. """
  358. authors = list(Author.objects.order_by("id"))
  359. for i in range(1, 5):
  360. author = authors[i - 1]
  361. article = getattr(self, "a%d" % (5 - i))
  362. article.author = author
  363. article.save(update_fields={"author"})
  364. self.assertQuerysetEqual(
  365. Article.objects.order_by("author_id"),
  366. [
  367. "Article 4",
  368. "Article 3",
  369. "Article 2",
  370. "Article 1",
  371. ],
  372. attrgetter("headline"),
  373. )
  374. def test_order_by_self_referential_fk(self):
  375. self.a1.author = Author.objects.create(editor=self.author_1)
  376. self.a1.save()
  377. self.a2.author = Author.objects.create(editor=self.author_2)
  378. self.a2.save()
  379. self.assertQuerysetEqual(
  380. Article.objects.filter(author__isnull=False).order_by("author__editor"),
  381. ["Article 2", "Article 1"],
  382. attrgetter("headline"),
  383. )
  384. self.assertQuerysetEqual(
  385. Article.objects.filter(author__isnull=False).order_by("author__editor_id"),
  386. ["Article 1", "Article 2"],
  387. attrgetter("headline"),
  388. )
  389. def test_order_by_f_expression(self):
  390. self.assertQuerysetEqual(
  391. Article.objects.order_by(F("headline")),
  392. [
  393. "Article 1",
  394. "Article 2",
  395. "Article 3",
  396. "Article 4",
  397. ],
  398. attrgetter("headline"),
  399. )
  400. self.assertQuerysetEqual(
  401. Article.objects.order_by(F("headline").asc()),
  402. [
  403. "Article 1",
  404. "Article 2",
  405. "Article 3",
  406. "Article 4",
  407. ],
  408. attrgetter("headline"),
  409. )
  410. self.assertQuerysetEqual(
  411. Article.objects.order_by(F("headline").desc()),
  412. [
  413. "Article 4",
  414. "Article 3",
  415. "Article 2",
  416. "Article 1",
  417. ],
  418. attrgetter("headline"),
  419. )
  420. def test_order_by_f_expression_duplicates(self):
  421. """
  422. A column may only be included once (the first occurrence) so we check
  423. to ensure there are no duplicates by inspecting the SQL.
  424. """
  425. qs = Article.objects.order_by(F("headline").asc(), F("headline").desc())
  426. sql = str(qs.query).upper()
  427. fragment = sql[sql.find("ORDER BY") :]
  428. self.assertEqual(fragment.count("HEADLINE"), 1)
  429. self.assertQuerysetEqual(
  430. qs,
  431. [
  432. "Article 1",
  433. "Article 2",
  434. "Article 3",
  435. "Article 4",
  436. ],
  437. attrgetter("headline"),
  438. )
  439. qs = Article.objects.order_by(F("headline").desc(), F("headline").asc())
  440. sql = str(qs.query).upper()
  441. fragment = sql[sql.find("ORDER BY") :]
  442. self.assertEqual(fragment.count("HEADLINE"), 1)
  443. self.assertQuerysetEqual(
  444. qs,
  445. [
  446. "Article 4",
  447. "Article 3",
  448. "Article 2",
  449. "Article 1",
  450. ],
  451. attrgetter("headline"),
  452. )
  453. def test_order_by_constant_value(self):
  454. # Order by annotated constant from selected columns.
  455. qs = Article.objects.annotate(
  456. constant=Value("1", output_field=CharField()),
  457. ).order_by("constant", "-headline")
  458. self.assertSequenceEqual(qs, [self.a4, self.a3, self.a2, self.a1])
  459. # Order by annotated constant which is out of selected columns.
  460. self.assertSequenceEqual(
  461. qs.values_list("headline", flat=True),
  462. [
  463. "Article 4",
  464. "Article 3",
  465. "Article 2",
  466. "Article 1",
  467. ],
  468. )
  469. # Order by constant.
  470. qs = Article.objects.order_by(Value("1", output_field=CharField()), "-headline")
  471. self.assertSequenceEqual(qs, [self.a4, self.a3, self.a2, self.a1])
  472. def test_related_ordering_duplicate_table_reference(self):
  473. """
  474. An ordering referencing a model with an ordering referencing a model
  475. multiple time no circular reference should be detected (#24654).
  476. """
  477. first_author = Author.objects.create()
  478. second_author = Author.objects.create()
  479. self.a1.author = first_author
  480. self.a1.second_author = second_author
  481. self.a1.save()
  482. self.a2.author = second_author
  483. self.a2.second_author = first_author
  484. self.a2.save()
  485. r1 = Reference.objects.create(article_id=self.a1.pk)
  486. r2 = Reference.objects.create(article_id=self.a2.pk)
  487. self.assertSequenceEqual(Reference.objects.all(), [r2, r1])
  488. def test_default_ordering_by_f_expression(self):
  489. """F expressions can be used in Meta.ordering."""
  490. articles = OrderedByFArticle.objects.all()
  491. articles.filter(headline="Article 2").update(author=self.author_2)
  492. articles.filter(headline="Article 3").update(author=self.author_1)
  493. self.assertQuerysetEqual(
  494. articles,
  495. ["Article 1", "Article 4", "Article 3", "Article 2"],
  496. attrgetter("headline"),
  497. )
  498. def test_order_by_ptr_field_with_default_ordering_by_expression(self):
  499. ca1 = ChildArticle.objects.create(
  500. headline="h2",
  501. pub_date=datetime(2005, 7, 27),
  502. author=self.author_2,
  503. )
  504. ca2 = ChildArticle.objects.create(
  505. headline="h2",
  506. pub_date=datetime(2005, 7, 27),
  507. author=self.author_1,
  508. )
  509. ca3 = ChildArticle.objects.create(
  510. headline="h3",
  511. pub_date=datetime(2005, 7, 27),
  512. author=self.author_1,
  513. )
  514. ca4 = ChildArticle.objects.create(headline="h1", pub_date=datetime(2005, 7, 28))
  515. articles = ChildArticle.objects.order_by("article_ptr")
  516. self.assertSequenceEqual(articles, [ca4, ca2, ca1, ca3])
  517. def test_default_ordering_does_not_affect_group_by(self):
  518. Article.objects.exclude(headline="Article 4").update(author=self.author_1)
  519. Article.objects.filter(headline="Article 4").update(author=self.author_2)
  520. articles = Article.objects.values("author").annotate(count=Count("author"))
  521. self.assertCountEqual(
  522. articles,
  523. [
  524. {"author": self.author_1.pk, "count": 3},
  525. {"author": self.author_2.pk, "count": 1},
  526. ],
  527. )
  528. def test_order_by_parent_fk_with_expression_in_default_ordering(self):
  529. p3 = OrderedByExpression.objects.create(name="oBJ 3")
  530. p2 = OrderedByExpression.objects.create(name="OBJ 2")
  531. p1 = OrderedByExpression.objects.create(name="obj 1")
  532. c3 = OrderedByExpressionChild.objects.create(parent=p3)
  533. c2 = OrderedByExpressionChild.objects.create(parent=p2)
  534. c1 = OrderedByExpressionChild.objects.create(parent=p1)
  535. self.assertSequenceEqual(
  536. OrderedByExpressionChild.objects.order_by("parent"),
  537. [c1, c2, c3],
  538. )
  539. def test_order_by_grandparent_fk_with_expression_in_default_ordering(self):
  540. p3 = OrderedByExpression.objects.create(name="oBJ 3")
  541. p2 = OrderedByExpression.objects.create(name="OBJ 2")
  542. p1 = OrderedByExpression.objects.create(name="obj 1")
  543. c3 = OrderedByExpressionChild.objects.create(parent=p3)
  544. c2 = OrderedByExpressionChild.objects.create(parent=p2)
  545. c1 = OrderedByExpressionChild.objects.create(parent=p1)
  546. g3 = OrderedByExpressionGrandChild.objects.create(parent=c3)
  547. g2 = OrderedByExpressionGrandChild.objects.create(parent=c2)
  548. g1 = OrderedByExpressionGrandChild.objects.create(parent=c1)
  549. self.assertSequenceEqual(
  550. OrderedByExpressionGrandChild.objects.order_by("parent"),
  551. [g1, g2, g3],
  552. )