阅读目录(Content)django
处理相似搭配 pizza 和 topping 这样简单的多对多关系时,使用标准的ManyToManyField 就能够了。可是,有时你可能须要关联数据到两个模型之间的关系上。code
例如,有这样一个应用,它记录音乐家所属的音乐小组。咱们能够用一个ManyToManyField 表示小组和成员之间的多对多关系。可是,有时你可能想知道更多成员关系的细节,好比成员是什么时候加入小组的。orm
对于这些状况,Django 容许你指定一个中介模型来定义多对多关系。 你能够将其余字段放在中介模型里面。源模型的ManyToManyField 字段将使用through 参数指向中介模型。对于上面的音乐小组的例子,代码以下:blog
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): # __unicode__ on Python 2 return self.name class Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
既然你已经设置好ManyToManyField 来使用中介模型(在这个例子中就是Membership),接下来你要开始建立多对多关系。你要作的就是建立中介模型的实例:ip
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason="Needed a new drummer.") >>> m1.save() >>> beatles.members.all() [<Person: Ringo Starr>] >>> ringo.group_set.all() [<Group: The Beatles>] >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason="Wanted to form a band.") >>> beatles.members.all() [<Person: Ringo Starr>, <Person: Paul McCartney>]
与普通的多对多字段不一样,你不能使用add、 create和赋值语句(好比,beatles.members = [...])来建立关系:unicode
# THIS WILL NOT WORK >>> beatles.members.add(john) # NEITHER WILL THIS >>> beatles.members.create(name="George Harrison") # AND NEITHER WILL THIS >>> beatles.members = [john, paul, ringo, george]
为何不能这样作? 这是由于你不能只建立 Person和 Group之间的关联关系,你还要指定 Membership模型中所须要的全部信息;而简单的add、create 和赋值语句是作不到这一点的。因此它们不能在使用中介模型的多对多关系中使用。此时,惟一的办法就是建立中介模型的实例。rem
remove()方法被禁用也是出于一样的缘由。可是clear() 方法倒是可用的。它能够清空某个实例全部的多对多关系
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() []