PageRenderTime 154ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/modeltests/many_to_one/tests.py

https://bitbucket.org/pcelta/python-django
Python | 426 lines | 337 code | 32 blank | 57 comment | 1 complexity | e4826e19fd6ee425ef97d55324700822 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. from __future__ import absolute_import, with_statement
  2. from copy import deepcopy
  3. from datetime import datetime
  4. from django.core.exceptions import MultipleObjectsReturned
  5. from django.test import TestCase
  6. from django.utils.translation import ugettext_lazy
  7. from .models import Article, Reporter
  8. class ManyToOneTests(TestCase):
  9. def setUp(self):
  10. # Create a few Reporters.
  11. self.r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
  12. self.r.save()
  13. self.r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
  14. self.r2.save()
  15. # Create an Article.
  16. self.a = Article(id=None, headline="This is a test",
  17. pub_date=datetime(2005, 7, 27), reporter=self.r)
  18. self.a.save()
  19. def test_get(self):
  20. # Article objects have access to their related Reporter objects.
  21. r = self.a.reporter
  22. self.assertEqual(r.id, self.r.id)
  23. # These are strings instead of unicode strings because that's what was used in
  24. # the creation of this reporter (and we haven't refreshed the data from the
  25. # database, which always returns unicode strings).
  26. self.assertEqual((r.first_name, self.r.last_name), ('John', 'Smith'))
  27. def test_create(self):
  28. # You can also instantiate an Article by passing the Reporter's ID
  29. # instead of a Reporter object.
  30. a3 = Article(id=None, headline="Third article",
  31. pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
  32. a3.save()
  33. self.assertEqual(a3.reporter.id, self.r.id)
  34. # Similarly, the reporter ID can be a string.
  35. a4 = Article(id=None, headline="Fourth article",
  36. pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
  37. a4.save()
  38. self.assertEqual(repr(a4.reporter), "<Reporter: John Smith>")
  39. def test_add(self):
  40. # Create an Article via the Reporter object.
  41. new_article = self.r.article_set.create(headline="John's second story",
  42. pub_date=datetime(2005, 7, 29))
  43. self.assertEqual(repr(new_article), "<Article: John's second story>")
  44. self.assertEqual(new_article.reporter.id, self.r.id)
  45. # Create a new article, and add it to the article set.
  46. new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17))
  47. self.r.article_set.add(new_article2)
  48. self.assertEqual(new_article2.reporter.id, self.r.id)
  49. self.assertQuerysetEqual(self.r.article_set.all(),
  50. [
  51. "<Article: John's second story>",
  52. "<Article: Paul's story>",
  53. "<Article: This is a test>",
  54. ])
  55. # Add the same article to a different article set - check that it moves.
  56. self.r2.article_set.add(new_article2)
  57. self.assertEqual(new_article2.reporter.id, self.r2.id)
  58. self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
  59. # Adding an object of the wrong type raises TypeError.
  60. with self.assertRaisesRegexp(TypeError, "'Article' instance expected, got <Reporter.*"):
  61. self.r.article_set.add(self.r2)
  62. self.assertQuerysetEqual(self.r.article_set.all(),
  63. [
  64. "<Article: John's second story>",
  65. "<Article: This is a test>",
  66. ])
  67. def test_assign(self):
  68. new_article = self.r.article_set.create(headline="John's second story",
  69. pub_date=datetime(2005, 7, 29))
  70. new_article2 = self.r2.article_set.create(headline="Paul's story",
  71. pub_date=datetime(2006, 1, 17))
  72. # Assign the article to the reporter directly using the descriptor.
  73. new_article2.reporter = self.r
  74. new_article2.save()
  75. self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
  76. self.assertEqual(new_article2.reporter.id, self.r.id)
  77. self.assertQuerysetEqual(self.r.article_set.all(), [
  78. "<Article: John's second story>",
  79. "<Article: Paul's story>",
  80. "<Article: This is a test>",
  81. ])
  82. self.assertQuerysetEqual(self.r2.article_set.all(), [])
  83. # Set the article back again using set descriptor.
  84. self.r2.article_set = [new_article, new_article2]
  85. self.assertQuerysetEqual(self.r.article_set.all(), ["<Article: This is a test>"])
  86. self.assertQuerysetEqual(self.r2.article_set.all(),
  87. [
  88. "<Article: John's second story>",
  89. "<Article: Paul's story>",
  90. ])
  91. # Funny case - assignment notation can only go so far; because the
  92. # ForeignKey cannot be null, existing members of the set must remain.
  93. self.r.article_set = [new_article]
  94. self.assertQuerysetEqual(self.r.article_set.all(),
  95. [
  96. "<Article: John's second story>",
  97. "<Article: This is a test>",
  98. ])
  99. self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's story>"])
  100. # Reporter cannot be null - there should not be a clear or remove method
  101. self.assertFalse(hasattr(self.r2.article_set, 'remove'))
  102. self.assertFalse(hasattr(self.r2.article_set, 'clear'))
  103. def test_selects(self):
  104. new_article = self.r.article_set.create(headline="John's second story",
  105. pub_date=datetime(2005, 7, 29))
  106. new_article2 = self.r2.article_set.create(headline="Paul's story",
  107. pub_date=datetime(2006, 1, 17))
  108. # Reporter objects have access to their related Article objects.
  109. self.assertQuerysetEqual(self.r.article_set.all(), [
  110. "<Article: John's second story>",
  111. "<Article: This is a test>",
  112. ])
  113. self.assertQuerysetEqual(self.r.article_set.filter(headline__startswith='This'),
  114. ["<Article: This is a test>"])
  115. self.assertEqual(self.r.article_set.count(), 2)
  116. self.assertEqual(self.r2.article_set.count(), 1)
  117. # Get articles by id
  118. self.assertQuerysetEqual(Article.objects.filter(id__exact=self.a.id),
  119. ["<Article: This is a test>"])
  120. self.assertQuerysetEqual(Article.objects.filter(pk=self.a.id),
  121. ["<Article: This is a test>"])
  122. # Query on an article property
  123. self.assertQuerysetEqual(Article.objects.filter(headline__startswith='This'),
  124. ["<Article: This is a test>"])
  125. # The API automatically follows relationships as far as you need.
  126. # Use double underscores to separate relationships.
  127. # This works as many levels deep as you want. There's no limit.
  128. # Find all Articles for any Reporter whose first name is "John".
  129. self.assertQuerysetEqual(Article.objects.filter(reporter__first_name__exact='John'),
  130. [
  131. "<Article: John's second story>",
  132. "<Article: This is a test>",
  133. ])
  134. # Check that implied __exact also works
  135. self.assertQuerysetEqual(Article.objects.filter(reporter__first_name='John'),
  136. [
  137. "<Article: John's second story>",
  138. "<Article: This is a test>",
  139. ])
  140. # Query twice over the related field.
  141. self.assertQuerysetEqual(
  142. Article.objects.filter(reporter__first_name__exact='John',
  143. reporter__last_name__exact='Smith'),
  144. [
  145. "<Article: John's second story>",
  146. "<Article: This is a test>",
  147. ])
  148. # The underlying query only makes one join when a related table is referenced twice.
  149. queryset = Article.objects.filter(reporter__first_name__exact='John',
  150. reporter__last_name__exact='Smith')
  151. self.assertNumQueries(1, list, queryset)
  152. self.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER JOIN'), 1)
  153. # The automatically joined table has a predictable name.
  154. self.assertQuerysetEqual(
  155. Article.objects.filter(reporter__first_name__exact='John').extra(
  156. where=["many_to_one_reporter.last_name='Smith'"]),
  157. [
  158. "<Article: John's second story>",
  159. "<Article: This is a test>",
  160. ])
  161. # ... and should work fine with the unicode that comes out of forms.Form.cleaned_data
  162. self.assertQuerysetEqual(
  163. Article.objects.filter(reporter__first_name__exact='John'
  164. ).extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith']),
  165. [
  166. "<Article: John's second story>",
  167. "<Article: This is a test>",
  168. ])
  169. # Find all Articles for a Reporter.
  170. # Use direct ID check, pk check, and object comparison
  171. self.assertQuerysetEqual(
  172. Article.objects.filter(reporter__id__exact=self.r.id),
  173. [
  174. "<Article: John's second story>",
  175. "<Article: This is a test>",
  176. ])
  177. self.assertQuerysetEqual(
  178. Article.objects.filter(reporter__pk=self.r.id),
  179. [
  180. "<Article: John's second story>",
  181. "<Article: This is a test>",
  182. ])
  183. self.assertQuerysetEqual(
  184. Article.objects.filter(reporter=self.r.id),
  185. [
  186. "<Article: John's second story>",
  187. "<Article: This is a test>",
  188. ])
  189. self.assertQuerysetEqual(
  190. Article.objects.filter(reporter=self.r),
  191. [
  192. "<Article: John's second story>",
  193. "<Article: This is a test>",
  194. ])
  195. self.assertQuerysetEqual(
  196. Article.objects.filter(reporter__in=[self.r.id,self.r2.id]).distinct(),
  197. [
  198. "<Article: John's second story>",
  199. "<Article: Paul's story>",
  200. "<Article: This is a test>",
  201. ])
  202. self.assertQuerysetEqual(
  203. Article.objects.filter(reporter__in=[self.r,self.r2]).distinct(),
  204. [
  205. "<Article: John's second story>",
  206. "<Article: Paul's story>",
  207. "<Article: This is a test>",
  208. ])
  209. # You can also use a queryset instead of a literal list of instances.
  210. # The queryset must be reduced to a list of values using values(),
  211. # then converted into a query
  212. self.assertQuerysetEqual(
  213. Article.objects.filter(
  214. reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
  215. ).distinct(),
  216. [
  217. "<Article: John's second story>",
  218. "<Article: This is a test>",
  219. ])
  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. self.assertEqual(repr(deepcopy(self.r)), "<Reporter: John Smith>")
  351. def test_explicit_fk(self):
  352. # Create a new Article with get_or_create using an explicit value
  353. # for a ForeignKey.
  354. a2, created = Article.objects.get_or_create(id=None,
  355. headline="John's second test",
  356. pub_date=datetime(2011, 5, 7),
  357. reporter_id=self.r.id)
  358. self.assertTrue(created)
  359. self.assertEqual(a2.reporter.id, self.r.id)
  360. # You can specify filters containing the explicit FK value.
  361. self.assertQuerysetEqual(
  362. Article.objects.filter(reporter_id__exact=self.r.id),
  363. [
  364. "<Article: John's second test>",
  365. "<Article: This is a test>",
  366. ])
  367. # Create an Article by Paul for the same date.
  368. a3 = Article.objects.create(id=None, headline="Paul's commentary",
  369. pub_date=datetime(2011, 5, 7),
  370. reporter_id=self.r2.id)
  371. self.assertEqual(a3.reporter.id, self.r2.id)
  372. # Get should respect explicit foreign keys as well.
  373. self.assertRaises(MultipleObjectsReturned,
  374. Article.objects.get, reporter_id=self.r.id)
  375. self.assertEqual(repr(a3),
  376. repr(Article.objects.get(reporter_id=self.r2.id,
  377. pub_date=datetime(2011, 5, 7))))
  378. def test_manager_class_caching(self):
  379. r1 = Reporter.objects.create(first_name='Mike')
  380. r2 = Reporter.objects.create(first_name='John')
  381. # Same twice
  382. self.assertTrue(r1.article_set.__class__ is r1.article_set.__class__)
  383. # Same as each other
  384. self.assertTrue(r1.article_set.__class__ is r2.article_set.__class__)
  385. def test_create_relation_with_ugettext_lazy(self):
  386. reporter = Reporter.objects.create(first_name='John',
  387. last_name='Smith',
  388. email='john.smith@example.com')
  389. lazy = ugettext_lazy(u'test')
  390. reporter.article_set.create(headline=lazy,
  391. pub_date=datetime(2011, 6, 10))
  392. notlazy = unicode(lazy)
  393. article = reporter.article_set.get()
  394. self.assertEqual(article.headline, notlazy)