~ubuntu-branches/ubuntu/jaunty/python-django/jaunty

« back to all changes in this revision

Viewing changes to tests/modeltests/m2m_through/models.py

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant, Eddy Mulyono
  • Date: 2008-09-16 12:18:47 UTC
  • mfrom: (1.1.5 upstream) (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080916121847-mg225rg5mnsdqzr0
Tags: 1.0-1ubuntu1
* Merge from Debian (LP: #264191), remaining changes:
  - Run test suite on build.

[Eddy Mulyono]
* Update patch to workaround network test case failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from django.db import models
 
2
from datetime import datetime
 
3
 
 
4
# M2M described on one of the models
 
5
class Person(models.Model):
 
6
    name = models.CharField(max_length=128)
 
7
 
 
8
    class Meta:
 
9
        ordering = ('name',)
 
10
 
 
11
    def __unicode__(self):
 
12
        return self.name
 
13
 
 
14
class Group(models.Model):
 
15
    name = models.CharField(max_length=128)
 
16
    members = models.ManyToManyField(Person, through='Membership')
 
17
    custom_members = models.ManyToManyField(Person, through='CustomMembership', related_name="custom")
 
18
    nodefaultsnonulls = models.ManyToManyField(Person, through='TestNoDefaultsOrNulls', related_name="testnodefaultsnonulls")
 
19
 
 
20
    class Meta:
 
21
        ordering = ('name',)
 
22
 
 
23
    def __unicode__(self):
 
24
        return self.name
 
25
 
 
26
class Membership(models.Model):
 
27
    person = models.ForeignKey(Person)
 
28
    group = models.ForeignKey(Group)
 
29
    date_joined = models.DateTimeField(default=datetime.now)
 
30
    invite_reason = models.CharField(max_length=64, null=True)
 
31
 
 
32
    class Meta:
 
33
        ordering = ('date_joined', 'invite_reason', 'group')
 
34
 
 
35
    def __unicode__(self):
 
36
        return "%s is a member of %s" % (self.person.name, self.group.name)
 
37
 
 
38
class CustomMembership(models.Model):
 
39
    person = models.ForeignKey(Person, db_column="custom_person_column", related_name="custom_person_related_name")
 
40
    group = models.ForeignKey(Group)
 
41
    weird_fk = models.ForeignKey(Membership, null=True)
 
42
    date_joined = models.DateTimeField(default=datetime.now)
 
43
 
 
44
    def __unicode__(self):
 
45
        return "%s is a member of %s" % (self.person.name, self.group.name)
 
46
 
 
47
    class Meta:
 
48
        db_table = "test_table"
 
49
 
 
50
class TestNoDefaultsOrNulls(models.Model):
 
51
    person = models.ForeignKey(Person)
 
52
    group = models.ForeignKey(Group)
 
53
    nodefaultnonull = models.CharField(max_length=5)
 
54
 
 
55
class PersonSelfRefM2M(models.Model):
 
56
    name = models.CharField(max_length=5)
 
57
    friends = models.ManyToManyField('self', through="Friendship", symmetrical=False)
 
58
 
 
59
    def __unicode__(self):
 
60
        return self.name
 
61
 
 
62
class Friendship(models.Model):
 
63
    first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set")
 
64
    second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set")
 
65
    date_friended = models.DateTimeField()
 
66
 
 
67
__test__ = {'API_TESTS':"""
 
68
>>> from datetime import datetime
 
69
 
 
70
### Creation and Saving Tests ###
 
71
 
 
72
>>> bob = Person.objects.create(name='Bob')
 
73
>>> jim = Person.objects.create(name='Jim')
 
74
>>> jane = Person.objects.create(name='Jane')
 
75
>>> rock = Group.objects.create(name='Rock')
 
76
>>> roll = Group.objects.create(name='Roll')
 
77
 
 
78
# We start out by making sure that the Group 'rock' has no members.
 
79
>>> rock.members.all()
 
80
[]
 
81
 
 
82
# To make Jim a member of Group Rock, simply create a Membership object.
 
83
>>> m1 = Membership.objects.create(person=jim, group=rock)
 
84
 
 
85
# We can do the same for Jane and Rock.
 
86
>>> m2 = Membership.objects.create(person=jane, group=rock)
 
87
 
 
88
# Let's check to make sure that it worked.  Jane and Jim should be members of Rock.
 
89
>>> rock.members.all()
 
90
[<Person: Jane>, <Person: Jim>]
 
91
 
 
92
# Now we can add a bunch more Membership objects to test with.
 
93
>>> m3 = Membership.objects.create(person=bob, group=roll)
 
94
>>> m4 = Membership.objects.create(person=jim, group=roll)
 
95
>>> m5 = Membership.objects.create(person=jane, group=roll)
 
96
 
 
97
# We can get Jim's Group membership as with any ForeignKey.
 
98
>>> jim.group_set.all()
 
99
[<Group: Rock>, <Group: Roll>]
 
100
 
 
101
# Querying the intermediary model works like normal.
 
102
# In this case we get Jane's membership to Rock.
 
103
>>> m = Membership.objects.get(person=jane, group=rock)
 
104
>>> m
 
105
<Membership: Jane is a member of Rock>
 
106
 
 
107
# Now we set some date_joined dates for further testing.
 
108
>>> m2.invite_reason = "She was just awesome."
 
109
>>> m2.date_joined = datetime(2006, 1, 1)
 
110
>>> m2.save()
 
111
 
 
112
>>> m5.date_joined = datetime(2004, 1, 1)
 
113
>>> m5.save()
 
114
 
 
115
>>> m3.date_joined = datetime(2004, 1, 1)
 
116
>>> m3.save()
 
117
 
 
118
# It's not only get that works. Filter works like normal as well.
 
119
>>> Membership.objects.filter(person=jim)
 
120
[<Membership: Jim is a member of Rock>, <Membership: Jim is a member of Roll>]
 
121
 
 
122
 
 
123
### Forward Descriptors Tests ###
 
124
 
 
125
# Due to complications with adding via an intermediary model,
 
126
# the add method is not provided.
 
127
>>> rock.members.add(bob)
 
128
Traceback (most recent call last):
 
129
...
 
130
AttributeError: 'ManyRelatedManager' object has no attribute 'add'
 
131
 
 
132
# Create is also disabled as it suffers from the same problems as add.
 
133
>>> rock.members.create(name='Anne')
 
134
Traceback (most recent call last):
 
135
...
 
136
AttributeError: Cannot use create() on a ManyToManyField which specifies an intermediary model. Use Membership's Manager instead.
 
137
 
 
138
# Remove has similar complications, and is not provided either.
 
139
>>> rock.members.remove(jim)
 
140
Traceback (most recent call last):
 
141
...
 
142
AttributeError: 'ManyRelatedManager' object has no attribute 'remove'
 
143
 
 
144
# Here we back up the list of all members of Rock.
 
145
>>> backup = list(rock.members.all())
 
146
 
 
147
# ...and we verify that it has worked.
 
148
>>> backup
 
149
[<Person: Jane>, <Person: Jim>]
 
150
 
 
151
# The clear function should still work.
 
152
>>> rock.members.clear()
 
153
 
 
154
# Now there will be no members of Rock.
 
155
>>> rock.members.all()
 
156
[]
 
157
 
 
158
# Assignment should not work with models specifying a through model for many of
 
159
# the same reasons as adding.
 
160
>>> rock.members = backup
 
161
Traceback (most recent call last):
 
162
...
 
163
AttributeError: Cannot set values on a ManyToManyField which specifies an intermediary model.  Use Membership's Manager instead.
 
164
 
 
165
# Let's re-save those instances that we've cleared.
 
166
>>> m1.save()
 
167
>>> m2.save()
 
168
 
 
169
# Verifying that those instances were re-saved successfully.
 
170
>>> rock.members.all()
 
171
[<Person: Jane>, <Person: Jim>]
 
172
 
 
173
 
 
174
### Reverse Descriptors Tests ###
 
175
 
 
176
# Due to complications with adding via an intermediary model,
 
177
# the add method is not provided.
 
178
>>> bob.group_set.add(rock)
 
179
Traceback (most recent call last):
 
180
...
 
181
AttributeError: 'ManyRelatedManager' object has no attribute 'add'
 
182
 
 
183
# Create is also disabled as it suffers from the same problems as add.
 
184
>>> bob.group_set.create(name='Funk')
 
185
Traceback (most recent call last):
 
186
...
 
187
AttributeError: Cannot use create() on a ManyToManyField which specifies an intermediary model. Use Membership's Manager instead.
 
188
 
 
189
# Remove has similar complications, and is not provided either.
 
190
>>> jim.group_set.remove(rock)
 
191
Traceback (most recent call last):
 
192
...
 
193
AttributeError: 'ManyRelatedManager' object has no attribute 'remove'
 
194
 
 
195
# Here we back up the list of all of Jim's groups.
 
196
>>> backup = list(jim.group_set.all())
 
197
>>> backup
 
198
[<Group: Rock>, <Group: Roll>]
 
199
 
 
200
# The clear function should still work.
 
201
>>> jim.group_set.clear()
 
202
 
 
203
# Now Jim will be in no groups.
 
204
>>> jim.group_set.all()
 
205
[]
 
206
 
 
207
# Assignment should not work with models specifying a through model for many of
 
208
# the same reasons as adding.
 
209
>>> jim.group_set = backup
 
210
Traceback (most recent call last):
 
211
...
 
212
AttributeError: Cannot set values on a ManyToManyField which specifies an intermediary model.  Use Membership's Manager instead.
 
213
 
 
214
# Let's re-save those instances that we've cleared.
 
215
>>> m1.save()
 
216
>>> m4.save()
 
217
 
 
218
# Verifying that those instances were re-saved successfully.
 
219
>>> jim.group_set.all()
 
220
[<Group: Rock>, <Group: Roll>]
 
221
 
 
222
### Custom Tests ###
 
223
 
 
224
# Let's see if we can query through our second relationship.
 
225
>>> rock.custom_members.all()
 
226
[]
 
227
 
 
228
# We can query in the opposite direction as well.
 
229
>>> bob.custom.all()
 
230
[]
 
231
 
 
232
# Let's create some membership objects in this custom relationship.
 
233
>>> cm1 = CustomMembership.objects.create(person=bob, group=rock)
 
234
>>> cm2 = CustomMembership.objects.create(person=jim, group=rock)
 
235
 
 
236
# If we get the number of people in Rock, it should be both Bob and Jim.
 
237
>>> rock.custom_members.all()
 
238
[<Person: Bob>, <Person: Jim>]
 
239
 
 
240
# Bob should only be in one custom group.
 
241
>>> bob.custom.all()
 
242
[<Group: Rock>]
 
243
 
 
244
# Let's make sure our new descriptors don't conflict with the FK related_name.
 
245
>>> bob.custom_person_related_name.all()
 
246
[<CustomMembership: Bob is a member of Rock>]
 
247
 
 
248
### SELF-REFERENTIAL TESTS ###
 
249
 
 
250
# Let's first create a person who has no friends.
 
251
>>> tony = PersonSelfRefM2M.objects.create(name="Tony")
 
252
>>> tony.friends.all()
 
253
[]
 
254
 
 
255
# Now let's create another person for Tony to be friends with.
 
256
>>> chris = PersonSelfRefM2M.objects.create(name="Chris")
 
257
>>> f = Friendship.objects.create(first=tony, second=chris, date_friended=datetime.now())
 
258
 
 
259
# Tony should now show that Chris is his friend.
 
260
>>> tony.friends.all()
 
261
[<PersonSelfRefM2M: Chris>]
 
262
 
 
263
# But we haven't established that Chris is Tony's Friend.
 
264
>>> chris.friends.all()
 
265
[]
 
266
 
 
267
# So let's do that now.
 
268
>>> f2 = Friendship.objects.create(first=chris, second=tony, date_friended=datetime.now())
 
269
 
 
270
# Having added Chris as a friend, let's make sure that his friend set reflects
 
271
# that addition.
 
272
>>> chris.friends.all()
 
273
[<PersonSelfRefM2M: Tony>]
 
274
 
 
275
# Chris gets mad and wants to get rid of all of his friends.
 
276
>>> chris.friends.clear()
 
277
 
 
278
# Now he should not have any more friends.
 
279
>>> chris.friends.all()
 
280
[]
 
281
 
 
282
# Since this isn't a symmetrical relation, Tony's friend link still exists.
 
283
>>> tony.friends.all()
 
284
[<PersonSelfRefM2M: Chris>]
 
285
 
 
286
 
 
287
 
 
288
### QUERY TESTS ###
 
289
 
 
290
# We can query for the related model by using its attribute name (members, in
 
291
# this case).
 
292
>>> Group.objects.filter(members__name='Bob')
 
293
[<Group: Roll>]
 
294
 
 
295
# To query through the intermediary model, we specify its model name.
 
296
# In this case, membership.
 
297
>>> Group.objects.filter(membership__invite_reason="She was just awesome.")
 
298
[<Group: Rock>]
 
299
 
 
300
# If we want to query in the reverse direction by the related model, use its
 
301
# model name (group, in this case).
 
302
>>> Person.objects.filter(group__name="Rock")
 
303
[<Person: Jane>, <Person: Jim>]
 
304
 
 
305
# If the m2m field has specified a related_name, using that will work.
 
306
>>> Person.objects.filter(custom__name="Rock")
 
307
[<Person: Bob>, <Person: Jim>]
 
308
 
 
309
# To query through the intermediary model in the reverse direction, we again
 
310
# specify its model name (membership, in this case).
 
311
>>> Person.objects.filter(membership__invite_reason="She was just awesome.")
 
312
[<Person: Jane>]
 
313
 
 
314
# Let's see all of the groups that Jane joined after 1 Jan 2005:
 
315
>>> Group.objects.filter(membership__date_joined__gt=datetime(2005, 1, 1), membership__person =jane)
 
316
[<Group: Rock>]
 
317
 
 
318
# Queries also work in the reverse direction: Now let's see all of the people
 
319
# that have joined Rock since 1 Jan 2005:
 
320
>>> Person.objects.filter(membership__date_joined__gt=datetime(2005, 1, 1), membership__group=rock)
 
321
[<Person: Jane>, <Person: Jim>]
 
322
 
 
323
# Conceivably, queries through membership could return correct, but non-unique
 
324
# querysets.  To demonstrate this, we query for all people who have joined a
 
325
# group after 2004:
 
326
>>> Person.objects.filter(membership__date_joined__gt=datetime(2004, 1, 1))
 
327
[<Person: Jane>, <Person: Jim>, <Person: Jim>]
 
328
 
 
329
# Jim showed up twice, because he joined two groups ('Rock', and 'Roll'):
 
330
>>> [(m.person.name, m.group.name) for m in
 
331
... Membership.objects.filter(date_joined__gt=datetime(2004, 1, 1))]
 
332
[(u'Jane', u'Rock'), (u'Jim', u'Rock'), (u'Jim', u'Roll')]
 
333
 
 
334
# QuerySet's distinct() method can correct this problem.
 
335
>>> Person.objects.filter(membership__date_joined__gt=datetime(2004, 1, 1)).distinct()
 
336
[<Person: Jane>, <Person: Jim>]
 
337
"""}
 
 
b'\\ No newline at end of file'