咱們以前學習圖書管理系統時,設計了Publish、Book、Author、AuthorDetail這樣幾張表,其中Book表和Author表是多對多關係,處理相似這樣簡單的多對多關係時,使用標準的ManyToManyField就能夠了。可是,有時你可能須要關聯數據到兩個模型之間的關係上。python
例如,有這樣一個應用,它記錄音樂家所屬的音樂小組。咱們能夠用一個ManyToManyField 表示小組和成員之間的多對多關係。可是,有時你可能想知道更多成員關係的細節,好比成員是什麼時候加入小組的。django
對於這些狀況,Django 容許你指定一箇中介模型來定義多對多關係。 你能夠將其餘字段放在中介模型裏面。原模型的ManyToManyField 字段將使用through 參數指向中介模型。對於上面的音樂小組的例子,代碼以下:學習
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", on_delete=models.CASCADE) group = models.ForeignKey("Group", on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
既然你已經設置好ManyToManyField 來使用中介模型(在這個例子中就是Membership),接下來你要開始建立多對多關係。你要作的就是建立中介模型的實例:this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
>>> ringo
=
Person.objects.create(name
=
"Ringo Starr"
)
# 建立一個音樂家ringo
>>> paul
=
Person.objects.create(name
=
"Paul McCartney"
)
# 建立一個音樂家paul
>>> beatles
=
Group.objects.create(name
=
"The Beatles"
)
# 建立一個音樂小組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 = [...])來建立關係:spa
1
2
3
4
5
6
|
# 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模型中所須要的全部信息(好比date_joined和invite_reason);而簡單的add、create 和賦值語句是作不到這一點的。因此它們不能在使用中介模型的多對多關係中使用。此時,惟一的辦法就是建立中介模型的實例。設計
remove()方法被禁用也是出於一樣的緣由。可是clear()方法倒是可用的。它能夠清空某個實例全部的多對多關係:code
1
2
3
4
5
|
# Beatles have broken up
>>> beatles.members.clear()
# Note that this deletes the intermediate model instances
>>> Membership.objects.
all
()
[]
|