PageRenderTime 312ms CodeModel.GetById 80ms app.highlight 102ms RepoModel.GetById 109ms app.codeStats 1ms

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