mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
Merged regressiontests and modeltests into the test root.
This commit is contained in:
345
tests/m2m_through/tests.py
Normal file
345
tests/m2m_through/tests.py
Normal file
@@ -0,0 +1,345 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from datetime import datetime
|
||||
from operator import attrgetter
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import (Person, Group, Membership, CustomMembership,
|
||||
PersonSelfRefM2M, Friendship)
|
||||
|
||||
|
||||
class M2mThroughTests(TestCase):
|
||||
def setUp(self):
|
||||
self.bob = Person.objects.create(name='Bob')
|
||||
self.jim = Person.objects.create(name='Jim')
|
||||
self.jane = Person.objects.create(name='Jane')
|
||||
self.rock = Group.objects.create(name='Rock')
|
||||
self.roll = Group.objects.create(name='Roll')
|
||||
|
||||
def test_m2m_through(self):
|
||||
# We start out by making sure that the Group 'rock' has no members.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.members.all(),
|
||||
[]
|
||||
)
|
||||
# To make Jim a member of Group Rock, simply create a Membership object.
|
||||
m1 = Membership.objects.create(person=self.jim, group=self.rock)
|
||||
# We can do the same for Jane and Rock.
|
||||
m2 = Membership.objects.create(person=self.jane, group=self.rock)
|
||||
# Let's check to make sure that it worked. Jane and Jim should be members of Rock.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.members.all(), [
|
||||
'Jane',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
# Now we can add a bunch more Membership objects to test with.
|
||||
m3 = Membership.objects.create(person=self.bob, group=self.roll)
|
||||
m4 = Membership.objects.create(person=self.jim, group=self.roll)
|
||||
m5 = Membership.objects.create(person=self.jane, group=self.roll)
|
||||
# We can get Jim's Group membership as with any ForeignKey.
|
||||
self.assertQuerysetEqual(
|
||||
self.jim.group_set.all(), [
|
||||
'Rock',
|
||||
'Roll'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
# Querying the intermediary model works like normal.
|
||||
self.assertEqual(
|
||||
repr(Membership.objects.get(person=self.jane, group=self.rock)),
|
||||
'<Membership: Jane is a member of Rock>'
|
||||
)
|
||||
# It's not only get that works. Filter works like normal as well.
|
||||
self.assertQuerysetEqual(
|
||||
Membership.objects.filter(person=self.jim), [
|
||||
'<Membership: Jim is a member of Rock>',
|
||||
'<Membership: Jim is a member of Roll>'
|
||||
]
|
||||
)
|
||||
self.rock.members.clear()
|
||||
# Now there will be no members of Rock.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.members.all(),
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
|
||||
def test_forward_descriptors(self):
|
||||
# Due to complications with adding via an intermediary model,
|
||||
# the add method is not provided.
|
||||
self.assertRaises(AttributeError, lambda: self.rock.members.add(self.bob))
|
||||
# Create is also disabled as it suffers from the same problems as add.
|
||||
self.assertRaises(AttributeError, lambda: self.rock.members.create(name='Anne'))
|
||||
# Remove has similar complications, and is not provided either.
|
||||
self.assertRaises(AttributeError, lambda: self.rock.members.remove(self.jim))
|
||||
|
||||
m1 = Membership.objects.create(person=self.jim, group=self.rock)
|
||||
m2 = Membership.objects.create(person=self.jane, group=self.rock)
|
||||
|
||||
# Here we back up the list of all members of Rock.
|
||||
backup = list(self.rock.members.all())
|
||||
# ...and we verify that it has worked.
|
||||
self.assertEqual(
|
||||
[p.name for p in backup],
|
||||
['Jane', 'Jim']
|
||||
)
|
||||
# The clear function should still work.
|
||||
self.rock.members.clear()
|
||||
# Now there will be no members of Rock.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.members.all(),
|
||||
[]
|
||||
)
|
||||
|
||||
# Assignment should not work with models specifying a through model for many of
|
||||
# the same reasons as adding.
|
||||
self.assertRaises(AttributeError, setattr, self.rock, "members", backup)
|
||||
# Let's re-save those instances that we've cleared.
|
||||
m1.save()
|
||||
m2.save()
|
||||
# Verifying that those instances were re-saved successfully.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.members.all(),[
|
||||
'Jane',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
def test_reverse_descriptors(self):
|
||||
# Due to complications with adding via an intermediary model,
|
||||
# the add method is not provided.
|
||||
self.assertRaises(AttributeError, lambda: self.bob.group_set.add(self.rock))
|
||||
# Create is also disabled as it suffers from the same problems as add.
|
||||
self.assertRaises(AttributeError, lambda: self.bob.group_set.create(name="funk"))
|
||||
# Remove has similar complications, and is not provided either.
|
||||
self.assertRaises(AttributeError, lambda: self.jim.group_set.remove(self.rock))
|
||||
|
||||
m1 = Membership.objects.create(person=self.jim, group=self.rock)
|
||||
m2 = Membership.objects.create(person=self.jim, group=self.roll)
|
||||
|
||||
# Here we back up the list of all of Jim's groups.
|
||||
backup = list(self.jim.group_set.all())
|
||||
self.assertEqual(
|
||||
[g.name for g in backup],
|
||||
['Rock', 'Roll']
|
||||
)
|
||||
# The clear function should still work.
|
||||
self.jim.group_set.clear()
|
||||
# Now Jim will be in no groups.
|
||||
self.assertQuerysetEqual(
|
||||
self.jim.group_set.all(),
|
||||
[]
|
||||
)
|
||||
# Assignment should not work with models specifying a through model for many of
|
||||
# the same reasons as adding.
|
||||
self.assertRaises(AttributeError, setattr, self.jim, "group_set", backup)
|
||||
# Let's re-save those instances that we've cleared.
|
||||
|
||||
m1.save()
|
||||
m2.save()
|
||||
# Verifying that those instances were re-saved successfully.
|
||||
self.assertQuerysetEqual(
|
||||
self.jim.group_set.all(),[
|
||||
'Rock',
|
||||
'Roll'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
def test_custom_tests(self):
|
||||
# Let's see if we can query through our second relationship.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.custom_members.all(),
|
||||
[]
|
||||
)
|
||||
# We can query in the opposite direction as well.
|
||||
self.assertQuerysetEqual(
|
||||
self.bob.custom.all(),
|
||||
[]
|
||||
)
|
||||
|
||||
cm1 = CustomMembership.objects.create(person=self.bob, group=self.rock)
|
||||
cm2 = CustomMembership.objects.create(person=self.jim, group=self.rock)
|
||||
|
||||
# If we get the number of people in Rock, it should be both Bob and Jim.
|
||||
self.assertQuerysetEqual(
|
||||
self.rock.custom_members.all(),[
|
||||
'Bob',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
# Bob should only be in one custom group.
|
||||
self.assertQuerysetEqual(
|
||||
self.bob.custom.all(),[
|
||||
'Rock'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
# Let's make sure our new descriptors don't conflict with the FK related_name.
|
||||
self.assertQuerysetEqual(
|
||||
self.bob.custom_person_related_name.all(),[
|
||||
'<CustomMembership: Bob is a member of Rock>'
|
||||
]
|
||||
)
|
||||
|
||||
def test_self_referential_tests(self):
|
||||
# Let's first create a person who has no friends.
|
||||
tony = PersonSelfRefM2M.objects.create(name="Tony")
|
||||
self.assertQuerysetEqual(
|
||||
tony.friends.all(),
|
||||
[]
|
||||
)
|
||||
|
||||
chris = PersonSelfRefM2M.objects.create(name="Chris")
|
||||
f = Friendship.objects.create(first=tony, second=chris, date_friended=datetime.now())
|
||||
|
||||
# Tony should now show that Chris is his friend.
|
||||
self.assertQuerysetEqual(
|
||||
tony.friends.all(),[
|
||||
'Chris'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
# But we haven't established that Chris is Tony's Friend.
|
||||
self.assertQuerysetEqual(
|
||||
chris.friends.all(),
|
||||
[]
|
||||
)
|
||||
f2 = Friendship.objects.create(first=chris, second=tony, date_friended=datetime.now())
|
||||
|
||||
# Having added Chris as a friend, let's make sure that his friend set reflects
|
||||
# that addition.
|
||||
self.assertQuerysetEqual(
|
||||
chris.friends.all(),[
|
||||
'Tony'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# Chris gets mad and wants to get rid of all of his friends.
|
||||
chris.friends.clear()
|
||||
# Now he should not have any more friends.
|
||||
self.assertQuerysetEqual(
|
||||
chris.friends.all(),
|
||||
[]
|
||||
)
|
||||
# Since this isn't a symmetrical relation, Tony's friend link still exists.
|
||||
self.assertQuerysetEqual(
|
||||
tony.friends.all(),[
|
||||
'Chris'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
def test_query_tests(self):
|
||||
m1 = Membership.objects.create(person=self.jim, group=self.rock)
|
||||
m2 = Membership.objects.create(person=self.jane, group=self.rock)
|
||||
m3 = Membership.objects.create(person=self.bob, group=self.roll)
|
||||
m4 = Membership.objects.create(person=self.jim, group=self.roll)
|
||||
m5 = Membership.objects.create(person=self.jane, group=self.roll)
|
||||
|
||||
m2.invite_reason = "She was just awesome."
|
||||
m2.date_joined = datetime(2006, 1, 1)
|
||||
m2.save()
|
||||
m3.date_joined = datetime(2004, 1, 1)
|
||||
m3.save()
|
||||
m5.date_joined = datetime(2004, 1, 1)
|
||||
m5.save()
|
||||
|
||||
# We can query for the related model by using its attribute name (members, in
|
||||
# this case).
|
||||
self.assertQuerysetEqual(
|
||||
Group.objects.filter(members__name='Bob'),[
|
||||
'Roll'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# To query through the intermediary model, we specify its model name.
|
||||
# In this case, membership.
|
||||
self.assertQuerysetEqual(
|
||||
Group.objects.filter(membership__invite_reason="She was just awesome."),[
|
||||
'Rock'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# If we want to query in the reverse direction by the related model, use its
|
||||
# model name (group, in this case).
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(group__name="Rock"),[
|
||||
'Jane',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
cm1 = CustomMembership.objects.create(person=self.bob, group=self.rock)
|
||||
cm2 = CustomMembership.objects.create(person=self.jim, group=self.rock)
|
||||
# If the m2m field has specified a related_name, using that will work.
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(custom__name="Rock"),[
|
||||
'Bob',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# To query through the intermediary model in the reverse direction, we again
|
||||
# specify its model name (membership, in this case).
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(membership__invite_reason="She was just awesome."),[
|
||||
'Jane'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# Let's see all of the groups that Jane joined after 1 Jan 2005:
|
||||
self.assertQuerysetEqual(
|
||||
Group.objects.filter(membership__date_joined__gt=datetime(2005, 1, 1), membership__person=self.jane),[
|
||||
'Rock'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# Queries also work in the reverse direction: Now let's see all of the people
|
||||
# that have joined Rock since 1 Jan 2005:
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(membership__date_joined__gt=datetime(2005, 1, 1), membership__group=self.rock),[
|
||||
'Jane',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# Conceivably, queries through membership could return correct, but non-unique
|
||||
# querysets. To demonstrate this, we query for all people who have joined a
|
||||
# group after 2004:
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(membership__date_joined__gt=datetime(2004, 1, 1)),[
|
||||
'Jane',
|
||||
'Jim',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
|
||||
# Jim showed up twice, because he joined two groups ('Rock', and 'Roll'):
|
||||
self.assertEqual(
|
||||
[(m.person.name, m.group.name) for m in Membership.objects.filter(date_joined__gt=datetime(2004, 1, 1))],
|
||||
[('Jane', 'Rock'), ('Jim', 'Rock'), ('Jim', 'Roll')]
|
||||
)
|
||||
# QuerySet's distinct() method can correct this problem.
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.filter(membership__date_joined__gt=datetime(2004, 1, 1)).distinct(),[
|
||||
'Jane',
|
||||
'Jim'
|
||||
],
|
||||
attrgetter("name")
|
||||
)
|
||||
Reference in New Issue
Block a user