tests.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. from __future__ import unicode_literals
  2. from datetime import datetime
  3. from operator import attrgetter
  4. from django.db.models import Q
  5. from django.test import TestCase
  6. from .models import Article
  7. class OrLookupsTests(TestCase):
  8. def setUp(self):
  9. self.a1 = Article.objects.create(
  10. headline='Hello', pub_date=datetime(2005, 11, 27)
  11. ).pk
  12. self.a2 = Article.objects.create(
  13. headline='Goodbye', pub_date=datetime(2005, 11, 28)
  14. ).pk
  15. self.a3 = Article.objects.create(
  16. headline='Hello and goodbye', pub_date=datetime(2005, 11, 29)
  17. ).pk
  18. def test_filter_or(self):
  19. self.assertQuerysetEqual(
  20. Article.objects.filter(headline__startswith='Hello') | Article.objects.filter(headline__startswith='Goodbye'), [
  21. 'Hello',
  22. 'Goodbye',
  23. 'Hello and goodbye'
  24. ],
  25. attrgetter("headline")
  26. )
  27. self.assertQuerysetEqual(
  28. Article.objects.filter(headline__contains='Hello') | Article.objects.filter(headline__contains='bye'), [
  29. 'Hello',
  30. 'Goodbye',
  31. 'Hello and goodbye'
  32. ],
  33. attrgetter("headline")
  34. )
  35. self.assertQuerysetEqual(
  36. Article.objects.filter(headline__iexact='Hello') | Article.objects.filter(headline__contains='ood'), [
  37. 'Hello',
  38. 'Goodbye',
  39. 'Hello and goodbye'
  40. ],
  41. attrgetter("headline")
  42. )
  43. self.assertQuerysetEqual(
  44. Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__startswith='Goodbye')), [
  45. 'Hello',
  46. 'Goodbye',
  47. 'Hello and goodbye'
  48. ],
  49. attrgetter("headline")
  50. )
  51. def test_stages(self):
  52. # You can shorten this syntax with code like the following, which is
  53. # especially useful if building the query in stages:
  54. articles = Article.objects.all()
  55. self.assertQuerysetEqual(
  56. articles.filter(headline__startswith='Hello') & articles.filter(headline__startswith='Goodbye'),
  57. []
  58. )
  59. self.assertQuerysetEqual(
  60. articles.filter(headline__startswith='Hello') & articles.filter(headline__contains='bye'), [
  61. 'Hello and goodbye'
  62. ],
  63. attrgetter("headline")
  64. )
  65. def test_pk_q(self):
  66. self.assertQuerysetEqual(
  67. Article.objects.filter(Q(pk=self.a1) | Q(pk=self.a2)), [
  68. 'Hello',
  69. 'Goodbye'
  70. ],
  71. attrgetter("headline")
  72. )
  73. self.assertQuerysetEqual(
  74. Article.objects.filter(Q(pk=self.a1) | Q(pk=self.a2) | Q(pk=self.a3)), [
  75. 'Hello',
  76. 'Goodbye',
  77. 'Hello and goodbye'
  78. ],
  79. attrgetter("headline"),
  80. )
  81. def test_pk_in(self):
  82. self.assertQuerysetEqual(
  83. Article.objects.filter(pk__in=[self.a1, self.a2, self.a3]), [
  84. 'Hello',
  85. 'Goodbye',
  86. 'Hello and goodbye'
  87. ],
  88. attrgetter("headline"),
  89. )
  90. self.assertQuerysetEqual(
  91. Article.objects.filter(pk__in=(self.a1, self.a2, self.a3)), [
  92. 'Hello',
  93. 'Goodbye',
  94. 'Hello and goodbye'
  95. ],
  96. attrgetter("headline"),
  97. )
  98. self.assertQuerysetEqual(
  99. Article.objects.filter(pk__in=[self.a1, self.a2, self.a3, 40000]), [
  100. 'Hello',
  101. 'Goodbye',
  102. 'Hello and goodbye'
  103. ],
  104. attrgetter("headline"),
  105. )
  106. def test_q_negated(self):
  107. # Q objects can be negated
  108. self.assertQuerysetEqual(
  109. Article.objects.filter(Q(pk=self.a1) | ~Q(pk=self.a2)), [
  110. 'Hello',
  111. 'Hello and goodbye'
  112. ],
  113. attrgetter("headline")
  114. )
  115. self.assertQuerysetEqual(
  116. Article.objects.filter(~Q(pk=self.a1) & ~Q(pk=self.a2)), [
  117. 'Hello and goodbye'
  118. ],
  119. attrgetter("headline"),
  120. )
  121. # This allows for more complex queries than filter() and exclude()
  122. # alone would allow
  123. self.assertQuerysetEqual(
  124. Article.objects.filter(Q(pk=self.a1) & (~Q(pk=self.a2) | Q(pk=self.a3))), [
  125. 'Hello'
  126. ],
  127. attrgetter("headline"),
  128. )
  129. def test_complex_filter(self):
  130. # The 'complex_filter' method supports framework features such as
  131. # 'limit_choices_to' which normally take a single dictionary of lookup
  132. # arguments but need to support arbitrary queries via Q objects too.
  133. self.assertQuerysetEqual(
  134. Article.objects.complex_filter({'pk': self.a1}), [
  135. 'Hello'
  136. ],
  137. attrgetter("headline"),
  138. )
  139. self.assertQuerysetEqual(
  140. Article.objects.complex_filter(Q(pk=self.a1) | Q(pk=self.a2)), [
  141. 'Hello',
  142. 'Goodbye'
  143. ],
  144. attrgetter("headline"),
  145. )
  146. def test_empty_in(self):
  147. # Passing "in" an empty list returns no results ...
  148. self.assertQuerysetEqual(
  149. Article.objects.filter(pk__in=[]),
  150. []
  151. )
  152. # ... but can return results if we OR it with another query.
  153. self.assertQuerysetEqual(
  154. Article.objects.filter(Q(pk__in=[]) | Q(headline__icontains='goodbye')), [
  155. 'Goodbye',
  156. 'Hello and goodbye'
  157. ],
  158. attrgetter("headline"),
  159. )
  160. def test_q_and(self):
  161. # Q arg objects are ANDed
  162. self.assertQuerysetEqual(
  163. Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')), [
  164. 'Hello and goodbye'
  165. ],
  166. attrgetter("headline")
  167. )
  168. # Q arg AND order is irrelevant
  169. self.assertQuerysetEqual(
  170. Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello'), [
  171. 'Hello and goodbye'
  172. ],
  173. attrgetter("headline"),
  174. )
  175. self.assertQuerysetEqual(
  176. Article.objects.filter(Q(headline__startswith='Hello') & Q(headline__startswith='Goodbye')),
  177. []
  178. )
  179. def test_q_exclude(self):
  180. self.assertQuerysetEqual(
  181. Article.objects.exclude(Q(headline__startswith='Hello')), [
  182. 'Goodbye'
  183. ],
  184. attrgetter("headline")
  185. )
  186. def test_other_arg_queries(self):
  187. # Try some arg queries with operations other than filter.
  188. self.assertEqual(
  189. Article.objects.get(Q(headline__startswith='Hello'), Q(headline__contains='bye')).headline,
  190. 'Hello and goodbye'
  191. )
  192. self.assertEqual(
  193. Article.objects.filter(Q(headline__startswith='Hello') | Q(headline__contains='bye')).count(),
  194. 3
  195. )
  196. self.assertQuerysetEqual(
  197. Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')).values(), [
  198. {"headline": "Hello and goodbye", "id": self.a3, "pub_date": datetime(2005, 11, 29)},
  199. ],
  200. lambda o: o,
  201. )
  202. self.assertEqual(
  203. Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([self.a1, self.a2]),
  204. {self.a1: Article.objects.get(pk=self.a1)}
  205. )