Author: russellm
Date: 2010-10-18 23:58:59 -0500 (Mon, 18 Oct 2010)
New Revision: 14281

Added:
   django/trunk/tests/modeltests/many_to_one/tests.py
Modified:
   django/trunk/tests/modeltests/many_to_one/models.py
Log:
Migrated many-to-one doctests. Thanks to George Sakkis for the patch.

Modified: django/trunk/tests/modeltests/many_to_one/models.py
===================================================================
--- django/trunk/tests/modeltests/many_to_one/models.py 2010-10-19 04:17:29 UTC 
(rev 14280)
+++ django/trunk/tests/modeltests/many_to_one/models.py 2010-10-19 04:58:59 UTC 
(rev 14281)
@@ -24,290 +24,3 @@
 
     class Meta:
         ordering = ('headline',)
-
-__test__ = {'API_TESTS':"""
-# Create a few Reporters.
->>> r = Reporter(first_name='John', last_name='Smith', 
email='j...@example.com')
->>> r.save()
-
->>> r2 = Reporter(first_name='Paul', last_name='Jones', 
email='p...@example.com')
->>> r2.save()
-
-# Create an Article.
->>> from datetime import datetime
->>> a = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 
27), reporter=r)
->>> a.save()
-
->>> a.reporter.id
-1
-
->>> a.reporter
-<Reporter: John Smith>
-
-# Article objects have access to their related Reporter objects.
->>> r = a.reporter
-
-# These are strings instead of unicode strings because that's what was used in
-# the creation of this reporter (and we haven't refreshed the data from the
-# database, which always returns unicode strings).
->>> r.first_name, r.last_name
-('John', 'Smith')
-
-# Create an Article via the Reporter object.
->>> new_article = r.article_set.create(headline="John's second story", 
pub_date=datetime(2005, 7, 29))
->>> new_article
-<Article: John's second story>
->>> new_article.reporter.id
-1
-
-# Create a new article, and add it to the article set.
->>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 
17))
->>> r.article_set.add(new_article2)
->>> new_article2.reporter.id
-1
->>> r.article_set.all()
-[<Article: John's second story>, <Article: Paul's story>, <Article: This is a 
test>]
-
-# Add the same article to a different article set - check that it moves.
->>> r2.article_set.add(new_article2)
->>> new_article2.reporter.id
-2
-
-# Adding an object of the wrong type raises TypeError
->>> r.article_set.add(r2)
-Traceback (most recent call last):
-...
-TypeError: 'Article' instance expected
-
->>> r.article_set.all()
-[<Article: John's second story>, <Article: This is a test>]
->>> r2.article_set.all()
-[<Article: Paul's story>]
-
-# Assign the article to the reporter directly using the descriptor
->>> new_article2.reporter = r
->>> new_article2.save()
->>> new_article2.reporter
-<Reporter: John Smith>
->>> new_article2.reporter.id
-1
->>> r.article_set.all()
-[<Article: John's second story>, <Article: Paul's story>, <Article: This is a 
test>]
->>> r2.article_set.all()
-[]
-
-# Set the article back again using set descriptor.
->>> r2.article_set = [new_article, new_article2]
->>> r.article_set.all()
-[<Article: This is a test>]
->>> r2.article_set.all()
-[<Article: John's second story>, <Article: Paul's story>]
-
-# Funny case - assignment notation can only go so far; because the
-# ForeignKey cannot be null, existing members of the set must remain
->>> r.article_set = [new_article]
->>> r.article_set.all()
-[<Article: John's second story>, <Article: This is a test>]
->>> r2.article_set.all()
-[<Article: Paul's story>]
-
-# Reporter cannot be null - there should not be a clear or remove method
->>> hasattr(r2.article_set, 'remove')
-False
->>> hasattr(r2.article_set, 'clear')
-False
-
-# Reporter objects have access to their related Article objects.
->>> r.article_set.all()
-[<Article: John's second story>, <Article: This is a test>]
-
->>> r.article_set.filter(headline__startswith='This')
-[<Article: This is a test>]
-
->>> r.article_set.count()
-2
-
->>> r2.article_set.count()
-1
-
-# Get articles by id
->>> Article.objects.filter(id__exact=1)
-[<Article: This is a test>]
->>> Article.objects.filter(pk=1)
-[<Article: This is a test>]
-
-# Query on an article property
->>> Article.objects.filter(headline__startswith='This')
-[<Article: This is a test>]
-
-# The API automatically follows relationships as far as you need.
-# Use double underscores to separate relationships.
-# This works as many levels deep as you want. There's no limit.
-# Find all Articles for any Reporter whose first name is "John".
->>> Article.objects.filter(reporter__first_name__exact='John')
-[<Article: John's second story>, <Article: This is a test>]
-
-# Check that implied __exact also works
->>> Article.objects.filter(reporter__first_name='John')
-[<Article: John's second story>, <Article: This is a test>]
-
-# Query twice over the related field.
->>> Article.objects.filter(reporter__first_name__exact='John', 
reporter__last_name__exact='Smith')
-[<Article: John's second story>, <Article: This is a test>]
-
-# The underlying query only makes one join when a related table is referenced 
twice.
->>> queryset = Article.objects.filter(reporter__first_name__exact='John', 
reporter__last_name__exact='Smith')
->>> sql = queryset.query.get_compiler(queryset.db).as_sql()[0]
->>> sql.count('INNER JOIN')
-1
-
-# The automatically joined table has a predictable name.
->>> 
Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='Smith'"])
-[<Article: John's second story>, <Article: This is a test>]
-
-# And should work fine with the unicode that comes out of
-# forms.Form.cleaned_data
->>> 
Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='%s'"
 % u'Smith'])
-[<Article: John's second story>, <Article: This is a test>]
-
-# Find all Articles for the Reporter whose ID is 1.
-# Use direct ID check, pk check, and object comparison
->>> Article.objects.filter(reporter__id__exact=1)
-[<Article: John's second story>, <Article: This is a test>]
->>> Article.objects.filter(reporter__pk=1)
-[<Article: John's second story>, <Article: This is a test>]
->>> Article.objects.filter(reporter=1)
-[<Article: John's second story>, <Article: This is a test>]
->>> Article.objects.filter(reporter=r)
-[<Article: John's second story>, <Article: This is a test>]
-
->>> Article.objects.filter(reporter__in=[1,2]).distinct()
-[<Article: John's second story>, <Article: Paul's story>, <Article: This is a 
test>]
->>> Article.objects.filter(reporter__in=[r,r2]).distinct()
-[<Article: John's second story>, <Article: Paul's story>, <Article: This is a 
test>]
-
-# You can also use a queryset instead of a literal list of instances.
-# The queryset must be reduced to a list of values using values(),
-# then converted into a query
->>> 
Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John').values('pk').query).distinct()
-[<Article: John's second story>, <Article: This is a test>]
-
-# You need two underscores between "reporter" and "id" -- not one.
->>> Article.objects.filter(reporter_id__exact=1)
-Traceback (most recent call last):
-    ...
-FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: 
headline, id, pub_date, reporter
-
-# You need to specify a comparison clause
->>> Article.objects.filter(reporter_id=1)
-Traceback (most recent call last):
-    ...
-FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: 
headline, id, pub_date, reporter
-
-# You can also instantiate an Article by passing
-# the Reporter's ID instead of a Reporter object.
->>> a3 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 
7, 27), reporter_id=r.id)
->>> a3.save()
->>> a3.reporter.id
-1
->>> a3.reporter
-<Reporter: John Smith>
-
-# Similarly, the reporter ID can be a string.
->>> a4 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 
7, 27), reporter_id="1")
->>> a4.save()
->>> a4.reporter
-<Reporter: John Smith>
-
-# Reporters can be queried
->>> Reporter.objects.filter(id__exact=1)
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(pk=1)
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(first_name__startswith='John')
-[<Reporter: John Smith>]
-
-# Reporters can query in opposite direction of ForeignKey definition
->>> Reporter.objects.filter(article__id__exact=1)
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article__pk=1)
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article=1)
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article=a)
-[<Reporter: John Smith>]
-
->>> Reporter.objects.filter(article__in=[1,4]).distinct()
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article__in=[1,a3]).distinct()
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article__in=[a,a3]).distinct()
-[<Reporter: John Smith>]
-
->>> Reporter.objects.filter(article__headline__startswith='This')
-[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
->>> Reporter.objects.filter(article__headline__startswith='This').distinct()
-[<Reporter: John Smith>]
-
-# Counting in the opposite direction works in conjunction with distinct()
->>> Reporter.objects.filter(article__headline__startswith='This').count()
-3
->>> 
Reporter.objects.filter(article__headline__startswith='This').distinct().count()
-1
-
-# Queries can go round in circles.
->>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
-[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, 
<Reporter: John Smith>]
->>> 
Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
-[<Reporter: John Smith>]
->>> Reporter.objects.filter(article__reporter__exact=r).distinct()
-[<Reporter: John Smith>]
-
-# Regression for #12876 -- Model methods that include queries that
-# recursive don't cause recursion depth problems under deepcopy.
->>> r.cached_query = Article.objects.filter(reporter=r)
->>> from copy import deepcopy
->>> deepcopy(r)
-<Reporter: John Smith>
-
-# Check that implied __exact also works.
->>> Reporter.objects.filter(article__reporter=r).distinct()
-[<Reporter: John Smith>]
-
-# It's possible to use values() calls across many-to-one relations. (Note, 
too, that we clear the ordering here so as not to drag the 'headline' field 
into the columns being used to determine uniqueness.)
->>> d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'}
->>> 
list(Article.objects.filter(reporter=r).distinct().order_by().values('reporter__first_name',
 'reporter__last_name')) == [d]
-True
-
-# If you delete a reporter, his articles will be deleted.
->>> Article.objects.all()
-[<Article: John's second story>, <Article: Paul's story>, <Article: This is a 
test>, <Article: This is a test>, <Article: This is a test>]
->>> Reporter.objects.order_by('first_name')
-[<Reporter: John Smith>, <Reporter: Paul Jones>]
->>> r2.delete()
->>> Article.objects.all()
-[<Article: John's second story>, <Article: This is a test>, <Article: This is 
a test>, <Article: This is a test>]
->>> Reporter.objects.order_by('first_name')
-[<Reporter: John Smith>]
-
-# You can delete using a JOIN in the query.
->>> Reporter.objects.filter(article__headline__startswith='This').delete()
->>> Reporter.objects.all()
-[]
->>> Article.objects.all()
-[]
-
-# Check that Article.objects.select_related().dates() works properly when
-# there are multiple Articles with the same date but different foreign-key
-# objects (Reporters).
->>> r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', 
email='ro...@suntimes.com')
->>> r2 = Reporter.objects.create(first_name='John', last_name='Kass', 
email='jk...@tribune.com')
->>> a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 4, 
23), reporter=r1)
->>> a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 4, 
23), reporter=r2)
->>> Article.objects.select_related().dates('pub_date', 'day')
-[datetime.datetime(1980, 4, 23, 0, 0)]
->>> Article.objects.select_related().dates('pub_date', 'month')
-[datetime.datetime(1980, 4, 1, 0, 0)]
->>> Article.objects.select_related().dates('pub_date', 'year')
-[datetime.datetime(1980, 1, 1, 0, 0)]
-"""}

Added: django/trunk/tests/modeltests/many_to_one/tests.py
===================================================================
--- django/trunk/tests/modeltests/many_to_one/tests.py                          
(rev 0)
+++ django/trunk/tests/modeltests/many_to_one/tests.py  2010-10-19 04:58:59 UTC 
(rev 14281)
@@ -0,0 +1,372 @@
+from datetime import datetime
+from django.test import TestCase
+from django.core.exceptions import FieldError
+from models import Article, Reporter
+
+class ManyToOneTests(TestCase):
+
+    def setUp(self):
+        # Create a few Reporters.
+        self.r = Reporter(first_name='John', last_name='Smith', 
email='j...@example.com')
+        self.r.save()
+        self.r2 = Reporter(first_name='Paul', last_name='Jones', 
email='p...@example.com')
+        self.r2.save()
+        # Create an Article.
+        self.a = Article(id=None, headline="This is a test",
+                         pub_date=datetime(2005, 7, 27), reporter=self.r)
+        self.a.save()
+
+    def test_get(self):
+        # Article objects have access to their related Reporter objects.
+        r = self.a.reporter
+        self.assertEqual(r.id, self.r.id)
+        # These are strings instead of unicode strings because that's what was 
used in
+        # the creation of this reporter (and we haven't refreshed the data 
from the
+        # database, which always returns unicode strings).
+        self.assertEqual((r.first_name, self.r.last_name), ('John', 'Smith'))
+
+    def test_create(self):
+        # You can also instantiate an Article by passing the Reporter's ID
+        # instead of a Reporter object.
+        a3 = Article(id=None, headline="Third article",
+                     pub_date=datetime(2005, 7, 27), reporter_id=self.r.id)
+        a3.save()
+        self.assertEqual(a3.reporter.id, self.r.id)
+
+        # Similarly, the reporter ID can be a string.
+        a4 = Article(id=None, headline="Fourth article",
+                     pub_date=datetime(2005, 7, 27), 
reporter_id=str(self.r.id))
+        a4.save()
+        self.assertEqual(repr(a4.reporter), "<Reporter: John Smith>")
+
+    def test_add(self):
+        # Create an Article via the Reporter object.
+        new_article = self.r.article_set.create(headline="John's second story",
+                                                pub_date=datetime(2005, 7, 29))
+        self.assertEqual(repr(new_article), "<Article: John's second story>")
+        self.assertEqual(new_article.reporter.id, self.r.id)
+
+        # Create a new article, and add it to the article set.
+        new_article2 = Article(headline="Paul's story", 
pub_date=datetime(2006, 1, 17))
+        self.r.article_set.add(new_article2)
+        self.assertEqual(new_article2.reporter.id, self.r.id)
+        self.assertQuerysetEqual(self.r.article_set.all(),
+            [
+                "<Article: John's second story>",
+                "<Article: Paul's story>",
+                "<Article: This is a test>",
+            ])
+
+        # Add the same article to a different article set - check that it 
moves.
+        self.r2.article_set.add(new_article2)
+        self.assertEqual(new_article2.reporter.id, self.r2.id)
+        self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's 
story>"])
+
+        # Adding an object of the wrong type raises TypeError.
+        self.assertRaises(TypeError, self.r.article_set.add, self.r2)
+        self.assertQuerysetEqual(self.r.article_set.all(),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+
+    def test_assign(self):
+        new_article = self.r.article_set.create(headline="John's second story",
+                                                pub_date=datetime(2005, 7, 29))
+        new_article2 = self.r2.article_set.create(headline="Paul's story",
+                                                  pub_date=datetime(2006, 1, 
17))
+        # Assign the article to the reporter directly using the descriptor.
+        new_article2.reporter = self.r
+        new_article2.save()
+        self.assertEqual(repr(new_article2.reporter), "<Reporter: John Smith>")
+        self.assertEqual(new_article2.reporter.id, self.r.id)
+        self.assertQuerysetEqual(self.r.article_set.all(), [
+            "<Article: John's second story>",
+            "<Article: Paul's story>",
+            "<Article: This is a test>",
+        ])
+        self.assertQuerysetEqual(self.r2.article_set.all(), [])
+        # Set the article back again using set descriptor.
+        self.r2.article_set = [new_article, new_article2]
+        self.assertQuerysetEqual(self.r.article_set.all(), ["<Article: This is 
a test>"])
+        self.assertQuerysetEqual(self.r2.article_set.all(),
+            [
+                "<Article: John's second story>",
+                "<Article: Paul's story>",
+            ])
+
+        # Funny case - assignment notation can only go so far; because the
+        # ForeignKey cannot be null, existing members of the set must remain.
+        self.r.article_set = [new_article]
+        self.assertQuerysetEqual(self.r.article_set.all(),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(self.r2.article_set.all(), ["<Article: Paul's 
story>"])
+        # Reporter cannot be null - there should not be a clear or remove 
method
+        self.assertFalse(hasattr(self.r2.article_set, 'remove'))
+        self.assertFalse(hasattr(self.r2.article_set, 'clear'))
+
+    def test_selects(self):
+        new_article = self.r.article_set.create(headline="John's second story",
+                                                pub_date=datetime(2005, 7, 29))
+        new_article2 = self.r2.article_set.create(headline="Paul's story",
+                                                  pub_date=datetime(2006, 1, 
17))
+        # Reporter objects have access to their related Article objects.
+        self.assertQuerysetEqual(self.r.article_set.all(), [
+            "<Article: John's second story>",
+            "<Article: This is a test>",
+        ])
+        
self.assertQuerysetEqual(self.r.article_set.filter(headline__startswith='This'),
+                                 ["<Article: This is a test>"])
+        self.assertEqual(self.r.article_set.count(), 2)
+        self.assertEqual(self.r2.article_set.count(), 1)
+        # Get articles by id
+        self.assertQuerysetEqual(Article.objects.filter(id__exact=self.a.id),
+                                 ["<Article: This is a test>"])
+        self.assertQuerysetEqual(Article.objects.filter(pk=self.a.id),
+                                 ["<Article: This is a test>"])
+        # Query on an article property
+        
self.assertQuerysetEqual(Article.objects.filter(headline__startswith='This'),
+                                 ["<Article: This is a test>"])
+        # The API automatically follows relationships as far as you need.
+        # Use double underscores to separate relationships.
+        # This works as many levels deep as you want. There's no limit.
+        # Find all Articles for any Reporter whose first name is "John".
+        
self.assertQuerysetEqual(Article.objects.filter(reporter__first_name__exact='John'),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # Check that implied __exact also works
+        
self.assertQuerysetEqual(Article.objects.filter(reporter__first_name='John'),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # Query twice over the related field.
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__first_name__exact='John',
+                                   reporter__last_name__exact='Smith'),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # The underlying query only makes one join when a related table is 
referenced twice.
+        queryset = Article.objects.filter(reporter__first_name__exact='John',
+                                       reporter__last_name__exact='Smith')
+        self.assertNumQueries(1, list, queryset)
+        
self.assertEqual(queryset.query.get_compiler(queryset.db).as_sql()[0].count('INNER
 JOIN'), 1)
+
+        # The automatically joined table has a predictable name.
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__first_name__exact='John').extra(
+                where=["many_to_one_reporter.last_name='Smith'"]),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # ... and should work fine with the unicode that comes out of 
forms.Form.cleaned_data
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__first_name__exact='John'
+                                  
).extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith']),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # Find all Articles for a Reporter.
+        # Use direct ID check, pk check, and object comparison
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__id__exact=self.r.id),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__pk=self.r.id),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter=self.r.id),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter=self.r),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(
+            
Article.objects.filter(reporter__in=[self.r.id,self.r2.id]).distinct(),
+            [
+                    "<Article: John's second story>",
+                    "<Article: Paul's story>",
+                    "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(
+            Article.objects.filter(reporter__in=[self.r,self.r2]).distinct(),
+            [
+                "<Article: John's second story>",
+                "<Article: Paul's story>",
+                "<Article: This is a test>",
+            ])
+        # You can also use a queryset instead of a literal list of instances.
+        # The queryset must be reduced to a list of values using values(),
+        # then converted into a query
+        self.assertQuerysetEqual(
+            Article.objects.filter(
+                        
reporter__in=Reporter.objects.filter(first_name='John').values('pk').query
+                    ).distinct(),
+            [
+                "<Article: John's second story>",
+                "<Article: This is a test>",
+            ])
+        # You need two underscores between "reporter" and "id" -- not one.
+        self.assertRaises(FieldError, Article.objects.filter, 
reporter_id__exact=self.r.id)
+        # You need to specify a comparison clause
+        self.assertRaises(FieldError, Article.objects.filter, 
reporter_id=self.r.id)
+
+    def test_reverse_selects(self):
+        a3 = Article.objects.create(id=None, headline="Third article",
+                                    pub_date=datetime(2005, 7, 27), 
reporter_id=self.r.id)
+        a4 = Article.objects.create(id=None, headline="Fourth article",
+                                    pub_date=datetime(2005, 7, 27), 
reporter_id=str(self.r.id))
+        # Reporters can be queried
+        self.assertQuerysetEqual(Reporter.objects.filter(id__exact=self.r.id),
+                                 ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(Reporter.objects.filter(pk=self.r.id),
+                                 ["<Reporter: John Smith>"])
+        
self.assertQuerysetEqual(Reporter.objects.filter(first_name__startswith='John'),
+                                 ["<Reporter: John Smith>"])
+        # Reporters can query in opposite direction of ForeignKey definition
+        
self.assertQuerysetEqual(Reporter.objects.filter(article__id__exact=self.a.id),
+                                 ["<Reporter: John Smith>"])
+        
self.assertQuerysetEqual(Reporter.objects.filter(article__pk=self.a.id),
+                                 ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(Reporter.objects.filter(article=self.a.id),
+                                 ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(Reporter.objects.filter(article=self.a),
+                                 ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            Reporter.objects.filter(article__in=[self.a.id,a3.id]).distinct(),
+            ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            Reporter.objects.filter(article__in=[self.a.id,a3]).distinct(),
+            ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            Reporter.objects.filter(article__in=[self.a,a3]).distinct(),
+            ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            Reporter.objects.filter(article__headline__startswith='T'),
+            ["<Reporter: John Smith>", "<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            
Reporter.objects.filter(article__headline__startswith='T').distinct(),
+            ["<Reporter: John Smith>"])
+
+        # Counting in the opposite direction works in conjunction with 
distinct()
+        self.assertEqual(
+            
Reporter.objects.filter(article__headline__startswith='T').count(), 2)
+        self.assertEqual(
+            
Reporter.objects.filter(article__headline__startswith='T').distinct().count(), 
1)
+
+        # Queries can go round in circles.
+        self.assertQuerysetEqual(
+            
Reporter.objects.filter(article__reporter__first_name__startswith='John'),
+            [
+                "<Reporter: John Smith>",
+                "<Reporter: John Smith>",
+                "<Reporter: John Smith>",
+            ])
+        self.assertQuerysetEqual(
+            
Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct(),
+            ["<Reporter: John Smith>"])
+        self.assertQuerysetEqual(
+            
Reporter.objects.filter(article__reporter__exact=self.r).distinct(),
+            ["<Reporter: John Smith>"])
+
+        # Check that implied __exact also works.
+        self.assertQuerysetEqual(
+            Reporter.objects.filter(article__reporter=self.r).distinct(),
+            ["<Reporter: John Smith>"])
+
+        # It's possible to use values() calls across many-to-one relations.
+        # (Note, too, that we clear the ordering here so as not to drag the
+        # 'headline' field into the columns being used to determine uniqueness)
+        d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'}
+        self.assertEqual([d],
+            list(Article.objects.filter(reporter=self.r).distinct().order_by()
+                 .values('reporter__first_name', 'reporter__last_name')))
+
+    def test_select_related(self):
+        # Check that Article.objects.select_related().dates() works properly 
when
+        # there are multiple Articles with the same date but different 
foreign-key
+        # objects (Reporters).
+        r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', 
email='ro...@suntimes.com')
+        r2 = Reporter.objects.create(first_name='John', last_name='Kass', 
email='jk...@tribune.com')
+        a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 
4, 23), reporter=r1)
+        a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 
4, 23), reporter=r2)
+        
self.assertEqual(list(Article.objects.select_related().dates('pub_date', 
'day')),
+            [
+                datetime(1980, 4, 23, 0, 0),
+                datetime(2005, 7, 27, 0, 0),
+            ])
+        
self.assertEqual(list(Article.objects.select_related().dates('pub_date', 
'month')),
+            [
+                datetime(1980, 4, 1, 0, 0),
+                datetime(2005, 7, 1, 0, 0),
+            ])
+        
self.assertEqual(list(Article.objects.select_related().dates('pub_date', 
'year')),
+            [
+                datetime(1980, 1, 1, 0, 0),
+                datetime(2005, 1, 1, 0, 0),
+            ])
+
+    def test_delete(self):
+        new_article = self.r.article_set.create(headline="John's second story",
+                                                pub_date=datetime(2005, 7, 29))
+        new_article2 = self.r2.article_set.create(headline="Paul's story",
+                                                  pub_date=datetime(2006, 1, 
17))
+        a3 = Article.objects.create(id=None, headline="Third article",
+                                    pub_date=datetime(2005, 7, 27), 
reporter_id=self.r.id)
+        a4 = Article.objects.create(id=None, headline="Fourth article",
+                                    pub_date=datetime(2005, 7, 27), 
reporter_id=str(self.r.id))
+        # If you delete a reporter, his articles will be deleted.
+        self.assertQuerysetEqual(Article.objects.all(),
+            [
+                "<Article: Fourth article>",
+                "<Article: John's second story>",
+                "<Article: Paul's story>",
+                "<Article: Third article>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
+            [
+                "<Reporter: John Smith>",
+                "<Reporter: Paul Jones>",
+            ])
+        self.r2.delete()
+        self.assertQuerysetEqual(Article.objects.all(),
+            [
+                "<Article: Fourth article>",
+                "<Article: John's second story>",
+                "<Article: Third article>",
+                "<Article: This is a test>",
+            ])
+        self.assertQuerysetEqual(Reporter.objects.order_by('first_name'),
+                                 ["<Reporter: John Smith>"])
+        # You can delete using a JOIN in the query.
+        Reporter.objects.filter(article__headline__startswith='This').delete()
+        self.assertQuerysetEqual(Reporter.objects.all(), [])
+        self.assertQuerysetEqual(Article.objects.all(), [])
+
+    def test_regression_12876(self):
+        # Regression for #12876 -- Model methods that include queries that
+        # recursive don't cause recursion depth problems under deepcopy.
+        self.r.cached_query = Article.objects.filter(reporter=self.r)
+        from copy import deepcopy
+        self.assertEqual(repr(deepcopy(self.r)), "<Reporter: John Smith>")

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to