| 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
|
|---|