1 | Ticket #6095 introduced the idea of custom intermediary models. Refractoring the m2m code to always use (generic) intermediary models would have benefits:
|
---|
2 | * a simplier implementation of m2m
|
---|
3 | * appropriate signals are always sent when a relation is created, modified or deleted (eg. #6778)
|
---|
4 | * extending the generic relations (using 'through=') would be easier
|
---|
5 | Of course, we must maintain compatibility to the m2m api, which consists (as far as I see it) of the ManyToManyField and the ManyRelatedManager. See the attachment for usage examples.
|
---|
6 |
|
---|
7 |
|
---|
8 | class Survey(models.Model):
|
---|
9 | participants = models.ManyToManyField(User)
|
---|
10 |
|
---|
11 | survey = Survey.objects.create()
|
---|
12 | # the m2m manager works as usual
|
---|
13 | survey.participants.add(User.objects.all())
|
---|
14 | survey.participants.remove(User.objects.get(pk=1))
|
---|
15 |
|
---|
16 | # with the benefit of signals
|
---|
17 | # lets assume Survey.participants.Relation is the generic intermediary model
|
---|
18 | def notify_of_survey(sender, instance):
|
---|
19 | survey, user = instance # do we need both objects as instance?..
|
---|
20 | user.notify(survey)
|
---|
21 | dispatcher.connect(notify_of_survey, signal=post_save, sender=Survey.participants.Relation)
|
---|
22 |
|
---|
23 | # on to another example
|
---|
24 | # the usage of through=
|
---|
25 | class Group(models.Model):
|
---|
26 | members = models.ManyToManyField(User, through='Membership')
|
---|
27 |
|
---|
28 | # as implemented in #6095
|
---|
29 | class Membership(models.Model):
|
---|
30 | user = models.ForeignKey(User)
|
---|
31 | group = models.ForeignKey(Group)
|
---|
32 | joined = models.DateField()
|
---|
33 |
|
---|
34 | # or even by extending the generic relation
|
---|
35 | # which would be abstract when through= is used.
|
---|
36 | class Membership(Group.members.Relation):
|
---|
37 | joined = models.DateField()
|
---|
38 |
|
---|
39 | group = Group.objects.create()
|
---|
40 | user = User.objects.get(pk=1)
|
---|
41 | # We should not remove add() etc. from the manager when using an intermediary model (as #6095 does)
|
---|
42 | group.members.add(user) # error from Membership.save()
|
---|
43 | group.members.add(user, joined=date) # OK
|
---|
44 | group.members.add(User.objects.all(), joined=date) # all with the same date
|
---|