PageRenderTime 34ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/modeltests/many_to_one/tests.py

https://code.google.com/p/mango-py/
Python | 372 lines | 299 code | 21 blank | 52 comment | 0 complexity | 269b4818f6aa11c1c68afe91619a7fbe MD5 | raw file
Possible License(s): BSD-3-Clause
  1. from datetime import datetime
  2. from django.test import TestCase
  3. from django.core.exceptions import FieldError
  4. from models import Article, Reporter
  5. class ManyToOneTests(TestCase):
  6. def setUp(self):
  7. # Create a few Reporters.
  8. self.r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
  9. self.r.save()
  10. self.r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
  11. self.r2.save()
  12. # Create an Article.
  13. self.a = Article(id=None, headline="This is a test",
  14. pub_date=datetime(2005, 7, 27), reporter=self.r)
  15. self.a.save()
  16. def test_get(self):
  17. # Article objects have access to their related Reporter objects.
  18. r = self.a.reporter
  19. self.assertEqual(r.id, self.r.id)
  20. # These are strings instead of unicode strings because that's what was used in
  21. # the creation of this reporter (and we haven't refreshed the data from the
  22. # database, which always returns unicode strings).
  23. self.assertEqual((r.first_name, self.r.last_name), ('John', 'Smith'))
  24. def test_create(self):
  25. # You can also instantiate an Article by passing the Reporter's ID
  26. # instead of a Reporter object.
  27. a3 = Article(id=None, headline="Third article",
  28. pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
  29. a3.save()
  30. self.assertEqual(a3.reporter.id, self.r.id)
  31. # Similarly, the reporter ID can be a string.
  32. a4 = Article(id=None, headline="Fourth article",
  33. pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
  34. a4.save()
  35. self.assertEqual(repr(a4.reporter), "<Reporter: John Smith>")
  36. def test_add(self):
  37. # Create an Article via the Reporter object.
  38. new_article = self.r.article_set.create(headline="John's second story",
  39. pub_date=datetime(2005, 7, 29))
  40. self.assertEqual(repr(new_article), "<Article: John's second story>")
  41. self.assertEqual(new_article.reporter.id, self.r.id)
  42. # Create a new article, and add it to the article set.
  43. new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17))
  44. self.r.article_set.add(new_article2)
  45. self.assertEqual(new_article2.reporter.id, self.r.id)
  46. self.assertQuerysetEqual(self.r.article_set.all(),
  47. [
  48. "<Article: John's second story>",
  49. "<Article: Paul's story>",
  50. "<Article: This is a test>",
  51. ])
  52. # Add the same article to a different article set - check that it moves.
  53. self.r2.article_set.add(new_article2)
  54. self.assertEqual(new_article2.reporter.id, self.r2.id)
  55. self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
  56. # Adding an object of the wrong type raises TypeError.
  57. self.assertRaises(TypeError, self.r.article_set.add, self.r2)
  58. self.assertQuerysetEqual(self.r.article_set.all(),
  59. [
  60. "<Article: John's second story>",
  61. "<Article: This is a test>",
  62. ])
  63. def test_assign(self):
  64. new_article = self.r.article_set.create(headline="John's second story",
  65. pub_date=datetime(2005, 7, 29))
  66. new_article2 = self.r2.article_set.create(headline="Paul's story",
  67. pub_date=datetime(2006, 1, 17))
  68. # Assign the article to the reporter directly using the descriptor.
  69. new_article2.reporter = self.r
  70. new_article2.save()
  71. self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
  72. self.assertEqual(new_article2.reporter.id, self.r.id)
  73. self.assertQuerysetEqual(self.r.article_set.all(), [
  74. "<Article: John's second story>",
  75. "<Article: Paul's story>",
  76. "<Article: This is a test>",
  77. ])
  78. self.assertQuerysetEqual(self.r2.article_set.all(), [])
  79. # Set the article back again using set descriptor.
  80. self.r2.article_set = [new_article, new_article2]
  81. self.assertQuerysetEqual(self.r.article_set.all(), ["<Article: This is a test>"])
  82. self.assertQuerysetEqual(self.r2.article_set.all(),
  83. [
  84. "<Article: John's second story>",
  85. "<Article: Paul's story>",
  86. ])
  87. # Funny case - assignment notation can only go so far; because the
  88. # ForeignKey cannot be null, existing members of the set must remain.
  89. self.r.article_set = [new_article]
  90. self.assertQuerysetEqual(self.r.article_set.all(),
  91. [
  92. "<Article: John's second story>",
  93. "<Article: This is a test>",
  94. ])
  95. self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
  96. # Reporter cannot be null - there should not be a clear or remove method
  97. self.assertFalse(hasattr(self.r2.article_set, 'remove'))
  98. self.assertFalse(hasattr(self.r2.article_set, 'clear'))
  99. def test_selects(self):
  100. new_article = self.r.article_set.create(headline="John's second story",
  101. pub_date=datetime(2005, 7, 29))
  102. new_article2 = self.r2.article_set.create(headline="Paul's story",
  103. pub_date=datetime(2006, 1, 17))
  104. # Reporter objects have access to their related Article objects.
  105. self.assertQuerysetEqual(self.r.article_set.all(), [
  106. "<Article: John's second story>",
  107. "<Article: This is a test>",
  108. ])
  109. self.assertQuerysetEqual(self.r.article_set.filter(headline__startswith='This'),
  110. ["<Article: This is a test>"])
  111. self.assertEqual(self.r.article_set.count(), 2)
  112. self.assertEqual(self.r2.article_set.count(), 1)
  113. # Get articles by id
  114. self.assertQuerysetEqual(Article.objects.filter(id__exact=self.a.id),
  115. ["<Article: This is a test>"])
  116. self.assertQuerysetEqual(Article.objects.filter(pk=self.a.id),
  117. ["<Article: This is a test>"])
  118. # Query on an article property
  119. self.assertQuerysetEqual(Article.objects.filter(headline__startswith='This'),
  120. ["<Article: This is a test>"])
  121. # The API automatically follows relationships as far as you need.
  122. # Use double underscores to separate relationships.
  123. # This works as many levels deep as you want. There's no limit.
  124. # Find all Articles for any Reporter whose first name is "John".
  125. self.assertQuerysetEqual(Article.objects.filter(reporter__first_name__exact='John'),
  126. [
  127. "<Article: John's second story>",
  128. "<Article: This is a test>",
  129. ])
  130. # Check that implied __exact also works
  131. self.assertQuerysetEqual(Article.objects.filter(reporter__first_name='John'),
  132. [
  133. "<Article: John's second story>",
  134. "<Article: This is a test>",
  135. ])
  136. # Query twice over the related field.
  137. self.assertQuerysetEqual(
  138. Article.objects.filter(reporter__first_name__exact='John',
  139. reporter__last_name__exact='Smith'),
  140. [
  141. "<Article: John's second story>",
  142. "<Article: This is a test>",
  143. ])
  144. # The underlying query only makes one join when a related table is referenced twice.
  145. queryset = Article.objects.filter(reporter__first_name__exact='John',
  146. reporter__last_name__exact='Smith')
  147. self.assertNumQueries(1, list, queryset)
  148. self.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER JOIN'), 1)
  149. # The automatically joined table has a predictable name.
  150. self.assertQuerysetEqual(
  151. Article.objects.filter(reporter__first_name__exact='John').extra(
  152. where=["many_to_one_reporter.last_name='Smith'"]),
  153. [
  154. "<Article: John's second story>",
  155. "<Article: This is a test>",
  156. ])
  157. # ... and should work fine with the unicode that comes out of forms.Form.cleaned_data
  158. self.assertQuerysetEqual(
  159. Article.objects.filter(reporter__first_name__exact='John'
  160. ).extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith']),
  161. [
  162. "<Article: John's second story>",
  163. "<Article: This is a test>",
  164. ])
  165. # Find all Articles for a Reporter.
  166. # Use direct ID check, pk check, and object comparison
  167. self.assertQuerysetEqual(
  168. Article.objects.filter(reporter__id__exact=self.r.id),
  169. [
  170. "<Article: John's second story>",
  171. "<Article: This is a test>",
  172. ])
  173. self.assertQuerysetEqual(
  174. Article.objects.filter(reporter__pk=self.r.id),
  175. [
  176. "<Article: John's second story>",
  177. "<Article: This is a test>",
  178. ])
  179. self.assertQuerysetEqual(
  180. Article.objects.filter(reporter=self.r.id),
  181. [
  182. "<Article: John's second story>",
  183. "<Article: This is a test>",
  184. ])
  185. self.assertQuerysetEqual(
  186. Article.objects.filter(reporter=self.r),
  187. [
  188. "<Article: John's second story>",
  189. "<Article: This is a test>",
  190. ])
  191. self.assertQuerysetEqual(
  192. Article.objects.filter(reporter__in=[self.r.id,self.r2.id]).distinct(),
  193. [
  194. "<Article: John's second story>",
  195. "<Article: Paul's story>",
  196. "<Article: This is a test>",
  197. ])
  198. self.assertQuerysetEqual(
  199. Article.objects.filter(reporter__in=[self.r,self.r2]).distinct(),
  200. [
  201. "<Article: John's second story>",
  202. "<Article: Paul's story>",
  203. "<Article: This is a test>",
  204. ])
  205. # You can also use a queryset instead of a literal list of instances.
  206. # The queryset must be reduced to a list of values using values(),
  207. # then converted into a query
  208. self.assertQuerysetEqual(
  209. Article.objects.filter(
  210. reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
  211. ).distinct(),
  212. [
  213. "<Article: John's second story>",
  214. "<Article: This is a test>",
  215. ])
  216. # You need two underscores between "reporter" and "id" -- not one.
  217. self.assertRaises(FieldError, Article.objects.filter, reporter_id__exact=self.r.id)
  218. # You need to specify a comparison clause
  219. self.assertRaises(FieldError, Article.objects.filter, reporter_id=self.r.id)
  220. def test_reverse_selects(self):
  221. a3 = Article.objects.create(id=None, headline="Third article",
  222. pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
  223. a4 = Article.objects.create(id=None, headline="Fourth article",
  224. pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
  225. # Reporters can be queried
  226. self.assertQuerysetEqual(Reporter.objects.filter(id__exact=self.r.id),
  227. ["<Reporter: John Smith>"])
  228. self.assertQuerysetEqual(Reporter.objects.filter(pk=self.r.id),
  229. ["<Reporter: John Smith>"])
  230. self.assertQuerysetEqual(Reporter.objects.filter(first_name__startswith='John'),
  231. ["<Reporter: John Smith>"])
  232. # Reporters can query in opposite direction of ForeignKey definition
  233. self.assertQuerysetEqual(Reporter.objects.filter(article__id__exact=self.a.id),
  234. ["<Reporter: John Smith>"])
  235. self.assertQuerysetEqual(Reporter.objects.filter(article__pk=self.a.id),
  236. ["<Reporter: John Smith>"])
  237. self.assertQuerysetEqual(Reporter.objects.filter(article=self.a.id),
  238. ["<Reporter: John Smith>"])
  239. self.assertQuerysetEqual(Reporter.objects.filter(article=self.a),
  240. ["<Reporter: John Smith>"])
  241. self.assertQuerysetEqual(
  242. Reporter.objects.filter(article__in=[self.a.id,a3.id]).distinct(),
  243. ["<Reporter: John Smith>"])
  244. self.assertQuerysetEqual(
  245. Reporter.objects.filter(article__in=[self.a.id,a3]).distinct(),
  246. ["<Reporter: John Smith>"])
  247. self.assertQuerysetEqual(
  248. Reporter.objects.filter(article__in=[self.a,a3]).distinct(),
  249. ["<Reporter: John Smith>"])
  250. self.assertQuerysetEqual(
  251. Reporter.objects.filter(article__headline__startswith='T'),
  252. ["<Reporter: John Smith>", "<Reporter: John Smith>"])
  253. self.assertQuerysetEqual(
  254. Reporter.objects.filter(article__headline__startswith='T').distinct(),
  255. ["<Reporter: John Smith>"])
  256. # Counting in the opposite direction works in conjunction with distinct()
  257. self.assertEqual(
  258. Reporter.objects.filter(article__headline__startswith='T').count(), 2)
  259. self.assertEqual(
  260. Reporter.objects.filter(article__headline__startswith='T').distinct().count(), 1)
  261. # Queries can go round in circles.
  262. self.assertQuerysetEqual(
  263. Reporter.objects.filter(article__reporter__first_name__startswith='John'),
  264. [
  265. "<Reporter: John Smith>",
  266. "<Reporter: John Smith>",
  267. "<Reporter: John Smith>",
  268. ])
  269. self.assertQuerysetEqual(
  270. Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct(),
  271. ["<Reporter: John Smith>"])
  272. self.assertQuerysetEqual(
  273. Reporter.objects.filter(article__reporter__exact=self.r).distinct(),
  274. ["<Reporter: John Smith>"])
  275. # Check that implied __exact also works.
  276. self.assertQuerysetEqual(
  277. Reporter.objects.filter(article__reporter=self.r).distinct(),
  278. ["<Reporter: John Smith>"])
  279. # It's possible to use values() calls across many-to-one relations.
  280. # (Note, too, that we clear the ordering here so as not to drag the
  281. # 'headline' field into the columns being used to determine uniqueness)
  282. d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'}
  283. self.assertEqual([d],
  284. list(Article.objects.filter(reporter=self.r).distinct().order_by()
  285. .values('reporter__first_name', 'reporter__last_name')))
  286. def test_select_related(self):
  287. # Check that Article.objects.select_related().dates() works properly when
  288. # there are multiple Articles with the same date but different foreign-key
  289. # objects (Reporters).
  290. r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', email='royko@suntimes.com')
  291. r2 = Reporter.objects.create(first_name='John', last_name='Kass', email='jkass@tribune.com')
  292. a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 4, 23), reporter=r1)
  293. a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 4, 23), reporter=r2)
  294. self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'day')),
  295. [
  296. datetime(1980, 4, 23, 0, 0),
  297. datetime(2005, 7, 27, 0, 0),
  298. ])
  299. self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'month')),
  300. [
  301. datetime(1980, 4, 1, 0, 0),
  302. datetime(2005, 7, 1, 0, 0),
  303. ])
  304. self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'year')),
  305. [
  306. datetime(1980, 1, 1, 0, 0),
  307. datetime(2005, 1, 1, 0, 0),
  308. ])
  309. def test_delete(self):
  310. new_article = self.r.article_set.create(headline="John's second story",
  311. pub_date=datetime(2005, 7, 29))
  312. new_article2 = self.r2.article_set.create(headline="Paul's story",
  313. pub_date=datetime(2006, 1, 17))
  314. a3 = Article.objects.create(id=None, headline="Third article",
  315. pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
  316. a4 = Article.objects.create(id=None, headline="Fourth article",
  317. pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
  318. # If you delete a reporter, his articles will be deleted.
  319. self.assertQuerysetEqual(Article.objects.all(),
  320. [
  321. "<Article: Fourth article>",
  322. "<Article: John's second story>",
  323. "<Article: Paul's story>",
  324. "<Article: Third article>",
  325. "<Article: This is a test>",
  326. ])
  327. self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
  328. [
  329. "<Reporter: John Smith>",
  330. "<Reporter: Paul Jones>",
  331. ])
  332. self.r2.delete()
  333. self.assertQuerysetEqual(Article.objects.all(),
  334. [
  335. "<Article: Fourth article>",
  336. "<Article: John's second story>",
  337. "<Article: Third article>",
  338. "<Article: This is a test>",
  339. ])
  340. self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
  341. ["<Reporter: John Smith>"])
  342. # You can delete using a JOIN in the query.
  343. Reporter.objects.filter(article__headline__startswith='This').delete()
  344. self.assertQuerysetEqual(Reporter.objects.all(), [])
  345. self.assertQuerysetEqual(Article.objects.all(), [])
  346. def test_regression_12876(self):
  347. # Regression for #12876 -- Model methods that include queries that
  348. # recursive don't cause recursion depth problems under deepcopy.
  349. self.r.cached_query = Article.objects.filter(reporter=self.r)
  350. from copy import deepcopy
  351. self.assertEqual(repr(deepcopy(self.r)), "<Reporter: John Smith>")