summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLoic Bistuer <loic.bistuer@gmail.com>2015-01-30 01:15:27 +0700
committerLoic Bistuer <loic.bistuer@gmail.com>2015-02-05 12:45:08 +0700
commit71ada3a8e689a883b5ffdeb1744ea16f176ab730 (patch)
tree7e4696ec75370e0747a26c4dea541626573895b2 /tests
parent49516f7158ed0ca39ea8116d25a32a80288d47b3 (diff)
Fixed #6707 -- Added RelatedManager.set() and made descriptors' __set__ use it.
Thanks Anssi Kääriäinen, Carl Meyer, Collin Anderson, and Tim Graham for the reviews.
Diffstat (limited to 'tests')
-rw-r--r--tests/generic_relations/tests.py52
-rw-r--r--tests/m2m_signals/tests.py90
-rw-r--r--tests/many_to_many/tests.py39
-rw-r--r--tests/many_to_one/tests.py39
-rw-r--r--tests/many_to_one_null/tests.py19
5 files changed, 194 insertions, 45 deletions
diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py
index c6230b057e..bc2cfaa579 100644
--- a/tests/generic_relations/tests.py
+++ b/tests/generic_relations/tests.py
@@ -246,6 +246,58 @@ class GenericRelationsTests(TestCase):
self.comp_func
)
+ def test_set(self):
+ bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
+ fatty = bacon.tags.create(tag="fatty")
+ salty = bacon.tags.create(tag="salty")
+
+ bacon.tags.set([fatty, salty])
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ "<TaggedItem: salty>",
+ ])
+
+ bacon.tags.set([fatty])
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ ])
+
+ bacon.tags.set([])
+ self.assertQuerysetEqual(bacon.tags.all(), [])
+
+ bacon.tags.set([fatty, salty], clear=True)
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ "<TaggedItem: salty>",
+ ])
+
+ bacon.tags.set([fatty], clear=True)
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ ])
+
+ bacon.tags.set([], clear=True)
+ self.assertQuerysetEqual(bacon.tags.all(), [])
+
+ def test_assign(self):
+ bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
+ fatty = bacon.tags.create(tag="fatty")
+ salty = bacon.tags.create(tag="salty")
+
+ bacon.tags = [fatty, salty]
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ "<TaggedItem: salty>",
+ ])
+
+ bacon.tags = [fatty]
+ self.assertQuerysetEqual(bacon.tags.all(), [
+ "<TaggedItem: fatty>",
+ ])
+
+ bacon.tags = []
+ self.assertQuerysetEqual(bacon.tags.all(), [])
+
def test_assign_with_queryset(self):
# Ensure that querysets used in reverse GFK assignments are pre-evaluated
# so their value isn't affected by the clearing operation in
diff --git a/tests/m2m_signals/tests.py b/tests/m2m_signals/tests.py
index ea4649551d..f41f6efd8e 100644
--- a/tests/m2m_signals/tests.py
+++ b/tests/m2m_signals/tests.py
@@ -254,15 +254,17 @@ class ManyToManySignalsTest(TestCase):
self.vw.default_parts = [self.wheelset, self.doors, self.engine]
expected_messages.append({
'instance': self.vw,
- 'action': 'pre_clear',
+ 'action': 'pre_remove',
'reverse': False,
'model': Part,
+ 'objects': [p6],
})
expected_messages.append({
'instance': self.vw,
- 'action': 'post_clear',
+ 'action': 'post_remove',
'reverse': False,
'model': Part,
+ 'objects': [p6],
})
expected_messages.append({
'instance': self.vw,
@@ -280,23 +282,59 @@ class ManyToManySignalsTest(TestCase):
})
self.assertEqual(self.m2m_changed_messages, expected_messages)
- # Check that signals still work when model inheritance is involved
- c4 = SportsCar.objects.create(name='Bugatti', price='1000000')
- c4b = Car.objects.get(name='Bugatti')
- c4.default_parts = [self.doors]
+ # set by clearing.
+ self.vw.default_parts.set([self.wheelset, self.doors, self.engine], clear=True)
expected_messages.append({
- 'instance': c4,
+ 'instance': self.vw,
'action': 'pre_clear',
'reverse': False,
'model': Part,
})
expected_messages.append({
- 'instance': c4,
+ 'instance': self.vw,
'action': 'post_clear',
'reverse': False,
'model': Part,
})
expected_messages.append({
+ 'instance': self.vw,
+ 'action': 'pre_add',
+ 'reverse': False,
+ 'model': Part,
+ 'objects': [self.doors, self.engine, self.wheelset],
+ })
+ expected_messages.append({
+ 'instance': self.vw,
+ 'action': 'post_add',
+ 'reverse': False,
+ 'model': Part,
+ 'objects': [self.doors, self.engine, self.wheelset],
+ })
+ self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+ # set by only removing what's necessary.
+ self.vw.default_parts.set([self.wheelset, self.doors], clear=False)
+ expected_messages.append({
+ 'instance': self.vw,
+ 'action': 'pre_remove',
+ 'reverse': False,
+ 'model': Part,
+ 'objects': [self.engine],
+ })
+ expected_messages.append({
+ 'instance': self.vw,
+ 'action': 'post_remove',
+ 'reverse': False,
+ 'model': Part,
+ 'objects': [self.engine],
+ })
+ self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+ # Check that signals still work when model inheritance is involved
+ c4 = SportsCar.objects.create(name='Bugatti', price='1000000')
+ c4b = Car.objects.get(name='Bugatti')
+ c4.default_parts = [self.doors]
+ expected_messages.append({
'instance': c4,
'action': 'pre_add',
'reverse': False,
@@ -342,18 +380,6 @@ class ManyToManySignalsTest(TestCase):
self.alice.friends = [self.bob, self.chuck]
expected_messages.append({
'instance': self.alice,
- 'action': 'pre_clear',
- 'reverse': False,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.alice,
- 'action': 'post_clear',
- 'reverse': False,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.alice,
'action': 'pre_add',
'reverse': False,
'model': Person,
@@ -371,18 +397,6 @@ class ManyToManySignalsTest(TestCase):
self.alice.fans = [self.daisy]
expected_messages.append({
'instance': self.alice,
- 'action': 'pre_clear',
- 'reverse': False,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.alice,
- 'action': 'post_clear',
- 'reverse': False,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.alice,
'action': 'pre_add',
'reverse': False,
'model': Person,
@@ -400,18 +414,6 @@ class ManyToManySignalsTest(TestCase):
self.chuck.idols = [self.alice, self.bob]
expected_messages.append({
'instance': self.chuck,
- 'action': 'pre_clear',
- 'reverse': True,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.chuck,
- 'action': 'post_clear',
- 'reverse': True,
- 'model': Person,
- })
- expected_messages.append({
- 'instance': self.chuck,
'action': 'pre_add',
'reverse': True,
'model': Person,
diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py
index adb897840a..192bc5f0e8 100644
--- a/tests/many_to_many/tests.py
+++ b/tests/many_to_many/tests.py
@@ -332,6 +332,45 @@ class ManyToManyTests(TestCase):
])
self.assertQuerysetEqual(self.a3.publications.all(), [])
+ def test_set(self):
+ self.p2.article_set.set([self.a4, self.a3])
+ self.assertQuerysetEqual(self.p2.article_set.all(),
+ [
+ '<Article: NASA finds intelligent life on Earth>',
+ '<Article: Oxygen-free diet works wonders>',
+ ])
+ self.assertQuerysetEqual(self.a4.publications.all(),
+ ['<Publication: Science News>'])
+ self.a4.publications.set([self.p3.id])
+ self.assertQuerysetEqual(self.p2.article_set.all(),
+ ['<Article: NASA finds intelligent life on Earth>'])
+ self.assertQuerysetEqual(self.a4.publications.all(),
+ ['<Publication: Science Weekly>'])
+
+ self.p2.article_set.set([])
+ self.assertQuerysetEqual(self.p2.article_set.all(), [])
+ self.a4.publications.set([])
+ self.assertQuerysetEqual(self.a4.publications.all(), [])
+
+ self.p2.article_set.set([self.a4, self.a3], clear=True)
+ self.assertQuerysetEqual(self.p2.article_set.all(),
+ [
+ '<Article: NASA finds intelligent life on Earth>',
+ '<Article: Oxygen-free diet works wonders>',
+ ])
+ self.assertQuerysetEqual(self.a4.publications.all(),
+ ['<Publication: Science News>'])
+ self.a4.publications.set([self.p3.id], clear=True)
+ self.assertQuerysetEqual(self.p2.article_set.all(),
+ ['<Article: NASA finds intelligent life on Earth>'])
+ self.assertQuerysetEqual(self.a4.publications.all(),
+ ['<Publication: Science Weekly>'])
+
+ self.p2.article_set.set([], clear=True)
+ self.assertQuerysetEqual(self.p2.article_set.all(), [])
+ self.a4.publications.set([], clear=True)
+ self.assertQuerysetEqual(self.a4.publications.all(), [])
+
def test_assign(self):
# Relation sets can be assigned. Assignment clears any existing set members
self.p2.article_set = [self.a4, self.a3]
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index e82d8eefe6..b66cfde9ed 100644
--- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -80,11 +80,49 @@ class ManyToOneTests(TestCase):
"<Article: This is a test>",
])
+ def test_set(self):
+ new_article = self.r.article_set.create(headline="John's second story",
+ pub_date=datetime.date(2005, 7, 29))
+ new_article2 = self.r2.article_set.create(headline="Paul's story",
+ pub_date=datetime.date(2006, 1, 17))
+
+ # Assign the article to the reporter.
+ 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.
+ self.r2.article_set.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 - because the ForeignKey cannot be null,
+ # existing members of the set must remain.
+ self.r.article_set.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>"])
+
def test_assign(self):
new_article = self.r.article_set.create(headline="John's second story",
pub_date=datetime.date(2005, 7, 29))
new_article2 = self.r2.article_set.create(headline="Paul's story",
pub_date=datetime.date(2006, 1, 17))
+
# Assign the article to the reporter directly using the descriptor.
new_article2.reporter = self.r
new_article2.save()
@@ -96,6 +134,7 @@ class ManyToOneTests(TestCase):
"<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>"])
diff --git a/tests/many_to_one_null/tests.py b/tests/many_to_one_null/tests.py
index a72b821f88..e39f527abe 100644
--- a/tests/many_to_one_null/tests.py
+++ b/tests/many_to_one_null/tests.py
@@ -74,9 +74,26 @@ class ManyToOneNullTests(TestCase):
self.assertRaises(Reporter.DoesNotExist, self.r.article_set.remove, self.a4)
self.assertQuerysetEqual(self.r2.article_set.all(), ['<Article: Fourth>'])
+ def test_set(self):
+ # Use manager.set() to allocate ForeignKey. Null is legal, so existing
+ # members of the set that are not in the assignment set are set to null.
+ self.r2.article_set.set([self.a2, self.a3])
+ self.assertQuerysetEqual(self.r2.article_set.all(),
+ ['<Article: Second>', '<Article: Third>'])
+ # Use manager.set(clear=True)
+ self.r2.article_set.set([self.a3, self.a4], clear=True)
+ self.assertQuerysetEqual(self.r2.article_set.all(),
+ ['<Article: Fourth>', '<Article: Third>'])
+ # Clear the rest of the set
+ self.r2.article_set.set([])
+ self.assertQuerysetEqual(self.r2.article_set.all(), [])
+ self.assertQuerysetEqual(Article.objects.filter(reporter__isnull=True),
+ ['<Article: Fourth>', '<Article: Second>', '<Article: Third>'])
+
def test_assign_clear_related_set(self):
# Use descriptor assignment to allocate ForeignKey. Null is legal, so
- # existing members of set that are not in the assignment set are set null
+ # existing members of the set that are not in the assignment set are
+ # set to null.
self.r2.article_set = [self.a2, self.a3]
self.assertQuerysetEqual(self.r2.article_set.all(),
['<Article: Second>', '<Article: Third>'])