中介模型(through)

假设我们要记录乐手和他们所属的乐队。我们可以用一个 ManyToManyField 表示乐手和乐队之间的多对多关系。但是,有时你可能想知道更多成员关系的细节,比如成员是何时加入乐队的加入乐队的原因是什么等。

对于这些情况,Django 允许你指定一个中介模型来定义多对多关系。 你可以将其他字段放在中介模型里面。源模型的 ManyToManyField 字段将使用 through 参数指向中介模型。对于上面的乐队的例子,代码如下:

from django.db import models

# 乐手
class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

# 乐队
class Group(models.Model):
    name = models.CharField(max_length=128)
    # 乐手和乐队之间通过中介模型 Membership 来联系
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        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)

创建乐手和乐队对象:

ringo = Person.objects.create(name="Ringo Starr")
paul = Person.objects.create(name="Paul McCartney")
beatles = Group.objects.create(name="The Beatles")

通过中介模型关联乐队和乐手:

from datetime import date

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

可见,乐队和乐手已经关联起来。

使用了中介模型以后,与普通的多对多字段不同,你不能使用 addcreate 和赋值语句(比如,beatles.members = [...])来创建关系:

# 不可以使用这些方法
beatles.members.add(john)
beatles.members.create(name="George Harrison")
beatles.members = [john, paul, ringo, george]

remove() 方法同样不能使用。但是 clear() 方法却是可用的。它可以清空某个实例所有的多对多关系:

beatles.members.clear()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容