parts/django/tests/modeltests/many_to_one/tests.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     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 
       
     6 class 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.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER JOIN'), 1)
       
   160 
       
   161         # The automatically joined table has a predictable name.
       
   162         self.assertQuerysetEqual(
       
   163             Article.objects.filter(reporter__first_name__exact='John').extra(
       
   164                 where=["many_to_one_reporter.last_name='Smith'"]),
       
   165             [
       
   166                 "<Article: John's second story>",
       
   167                 "<Article: This is a test>",
       
   168             ])
       
   169         # ... and should work fine with the unicode that comes out of forms.Form.cleaned_data
       
   170         self.assertQuerysetEqual(
       
   171             Article.objects.filter(reporter__first_name__exact='John'
       
   172                                   ).extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith']),
       
   173             [
       
   174                 "<Article: John's second story>",
       
   175                 "<Article: This is a test>",
       
   176             ])
       
   177         # Find all Articles for a Reporter.
       
   178         # Use direct ID check, pk check, and object comparison
       
   179         self.assertQuerysetEqual(
       
   180             Article.objects.filter(reporter__id__exact=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__pk=self.r.id),
       
   187             [
       
   188                 "<Article: John's second story>",
       
   189                 "<Article: This is a test>",
       
   190             ])
       
   191         self.assertQuerysetEqual(
       
   192             Article.objects.filter(reporter=self.r.id),
       
   193             [
       
   194                 "<Article: John's second story>",
       
   195                 "<Article: This is a test>",
       
   196             ])
       
   197         self.assertQuerysetEqual(
       
   198             Article.objects.filter(reporter=self.r),
       
   199             [
       
   200                 "<Article: John's second story>",
       
   201                 "<Article: This is a test>",
       
   202             ])
       
   203         self.assertQuerysetEqual(
       
   204             Article.objects.filter(reporter__in=[self.r.id,self.r2.id]).distinct(),
       
   205             [
       
   206                     "<Article: John's second story>",
       
   207                     "<Article: Paul's story>",
       
   208                     "<Article: This is a test>",
       
   209             ])
       
   210         self.assertQuerysetEqual(
       
   211             Article.objects.filter(reporter__in=[self.r,self.r2]).distinct(),
       
   212             [
       
   213                 "<Article: John's second story>",
       
   214                 "<Article: Paul's story>",
       
   215                 "<Article: This is a test>",
       
   216             ])
       
   217         # You can also use a queryset instead of a literal list of instances.
       
   218         # The queryset must be reduced to a list of values using values(),
       
   219         # then converted into a query
       
   220         self.assertQuerysetEqual(
       
   221             Article.objects.filter(
       
   222                         reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
       
   223                     ).distinct(),
       
   224             [
       
   225                 "<Article: John's second story>",
       
   226                 "<Article: This is a test>",
       
   227             ])
       
   228         # You need two underscores between "reporter" and "id" -- not one.
       
   229         self.assertRaises(FieldError, Article.objects.filter, reporter_id__exact=self.r.id)
       
   230         # You need to specify a comparison clause
       
   231         self.assertRaises(FieldError, Article.objects.filter, reporter_id=self.r.id)
       
   232 
       
   233     def test_reverse_selects(self):
       
   234         a3 = Article.objects.create(id=None, headline="Third article",
       
   235                                     pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
       
   236         a4 = Article.objects.create(id=None, headline="Fourth article",
       
   237                                     pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
       
   238         # Reporters can be queried
       
   239         self.assertQuerysetEqual(Reporter.objects.filter(id__exact=self.r.id),
       
   240                                  ["<Reporter: John Smith>"])
       
   241         self.assertQuerysetEqual(Reporter.objects.filter(pk=self.r.id),
       
   242                                  ["<Reporter: John Smith>"])
       
   243         self.assertQuerysetEqual(Reporter.objects.filter(first_name__startswith='John'),
       
   244                                  ["<Reporter: John Smith>"])
       
   245         # Reporters can query in opposite direction of ForeignKey definition
       
   246         self.assertQuerysetEqual(Reporter.objects.filter(article__id__exact=self.a.id),
       
   247                                  ["<Reporter: John Smith>"])
       
   248         self.assertQuerysetEqual(Reporter.objects.filter(article__pk=self.a.id),
       
   249                                  ["<Reporter: John Smith>"])
       
   250         self.assertQuerysetEqual(Reporter.objects.filter(article=self.a.id),
       
   251                                  ["<Reporter: John Smith>"])
       
   252         self.assertQuerysetEqual(Reporter.objects.filter(article=self.a),
       
   253                                  ["<Reporter: John Smith>"])
       
   254         self.assertQuerysetEqual(
       
   255             Reporter.objects.filter(article__in=[self.a.id,a3.id]).distinct(),
       
   256             ["<Reporter: John Smith>"])
       
   257         self.assertQuerysetEqual(
       
   258             Reporter.objects.filter(article__in=[self.a.id,a3]).distinct(),
       
   259             ["<Reporter: John Smith>"])
       
   260         self.assertQuerysetEqual(
       
   261             Reporter.objects.filter(article__in=[self.a,a3]).distinct(),
       
   262             ["<Reporter: John Smith>"])
       
   263         self.assertQuerysetEqual(
       
   264             Reporter.objects.filter(article__headline__startswith='T'),
       
   265             ["<Reporter: John Smith>", "<Reporter: John Smith>"])
       
   266         self.assertQuerysetEqual(
       
   267             Reporter.objects.filter(article__headline__startswith='T').distinct(),
       
   268             ["<Reporter: John Smith>"])
       
   269 
       
   270         # Counting in the opposite direction works in conjunction with distinct()
       
   271         self.assertEqual(
       
   272             Reporter.objects.filter(article__headline__startswith='T').count(), 2)
       
   273         self.assertEqual(
       
   274             Reporter.objects.filter(article__headline__startswith='T').distinct().count(), 1)
       
   275 
       
   276         # Queries can go round in circles.
       
   277         self.assertQuerysetEqual(
       
   278             Reporter.objects.filter(article__reporter__first_name__startswith='John'),
       
   279             [
       
   280                 "<Reporter: John Smith>",
       
   281                 "<Reporter: John Smith>",
       
   282                 "<Reporter: John Smith>",
       
   283             ])
       
   284         self.assertQuerysetEqual(
       
   285             Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct(),
       
   286             ["<Reporter: John Smith>"])
       
   287         self.assertQuerysetEqual(
       
   288             Reporter.objects.filter(article__reporter__exact=self.r).distinct(),
       
   289             ["<Reporter: John Smith>"])
       
   290 
       
   291         # Check that implied __exact also works.
       
   292         self.assertQuerysetEqual(
       
   293             Reporter.objects.filter(article__reporter=self.r).distinct(),
       
   294             ["<Reporter: John Smith>"])
       
   295 
       
   296         # It's possible to use values() calls across many-to-one relations.
       
   297         # (Note, too, that we clear the ordering here so as not to drag the
       
   298         # 'headline' field into the columns being used to determine uniqueness)
       
   299         d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'}
       
   300         self.assertEqual([d],
       
   301             list(Article.objects.filter(reporter=self.r).distinct().order_by()
       
   302                  .values('reporter__first_name', 'reporter__last_name')))
       
   303 
       
   304     def test_select_related(self):
       
   305         # Check that Article.objects.select_related().dates() works properly when
       
   306         # there are multiple Articles with the same date but different foreign-key
       
   307         # objects (Reporters).
       
   308         r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', email='royko@suntimes.com')
       
   309         r2 = Reporter.objects.create(first_name='John', last_name='Kass', email='jkass@tribune.com')
       
   310         a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 4, 23), reporter=r1)
       
   311         a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 4, 23), reporter=r2)
       
   312         self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'day')),
       
   313             [
       
   314                 datetime(1980, 4, 23, 0, 0),
       
   315                 datetime(2005, 7, 27, 0, 0),
       
   316             ])
       
   317         self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'month')),
       
   318             [
       
   319                 datetime(1980, 4, 1, 0, 0),
       
   320                 datetime(2005, 7, 1, 0, 0),
       
   321             ])
       
   322         self.assertEqual(list(Article.objects.select_related().dates('pub_date', 'year')),
       
   323             [
       
   324                 datetime(1980, 1, 1, 0, 0),
       
   325                 datetime(2005, 1, 1, 0, 0),
       
   326             ])
       
   327 
       
   328     def test_delete(self):
       
   329         new_article = self.r.article_set.create(headline="John's second story",
       
   330                                                 pub_date=datetime(2005, 7, 29))
       
   331         new_article2 = self.r2.article_set.create(headline="Paul's story",
       
   332                                                   pub_date=datetime(2006, 1, 17))
       
   333         a3 = Article.objects.create(id=None, headline="Third article",
       
   334                                     pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
       
   335         a4 = Article.objects.create(id=None, headline="Fourth article",
       
   336                                     pub_date=datetime(2005, 7, 27), reporter_id=str(self.r.id))
       
   337         # If you delete a reporter, his articles will be deleted.
       
   338         self.assertQuerysetEqual(Article.objects.all(),
       
   339             [
       
   340                 "<Article: Fourth article>",
       
   341                 "<Article: John's second story>",
       
   342                 "<Article: Paul's story>",
       
   343                 "<Article: Third article>",
       
   344                 "<Article: This is a test>",
       
   345             ])
       
   346         self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
       
   347             [
       
   348                 "<Reporter: John Smith>",
       
   349                 "<Reporter: Paul Jones>",
       
   350             ])
       
   351         self.r2.delete()
       
   352         self.assertQuerysetEqual(Article.objects.all(),
       
   353             [
       
   354                 "<Article: Fourth article>",
       
   355                 "<Article: John's second story>",
       
   356                 "<Article: Third article>",
       
   357                 "<Article: This is a test>",
       
   358             ])
       
   359         self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
       
   360                                  ["<Reporter: John Smith>"])
       
   361         # You can delete using a JOIN in the query.
       
   362         Reporter.objects.filter(article__headline__startswith='This').delete()
       
   363         self.assertQuerysetEqual(Reporter.objects.all(), [])
       
   364         self.assertQuerysetEqual(Article.objects.all(), [])
       
   365 
       
   366     def test_regression_12876(self):
       
   367         # Regression for #12876 -- Model methods that include queries that
       
   368         # recursive don't cause recursion depth problems under deepcopy.
       
   369         self.r.cached_query = Article.objects.filter(reporter=self.r)
       
   370         from copy import deepcopy
       
   371         self.assertEqual(repr(deepcopy(self.r)), "<Reporter: John Smith>")