Django - 回顧(2)- 中介模型
阿新 • • 發佈:2018-11-23
一、中介模型
我們之前學習圖書管理系統時,設計了Publish、Book、Author、AuthorDetail這樣幾張表,其中Book表和Author表是多對多關係,處理類似這樣簡單的多對多關係時,使用標準的ManyToManyField就可以了。但是,有時你可能需要關聯資料到兩個模型之間的關係上。
例如,有這樣一個應用,它記錄音樂家所屬的音樂小組。我們可以用一個ManyToManyField 表示小組和成員之間的多對多關係。但是,有時你可能想知道更多成員關係的細節,比如成員是何時加入小組的。
對於這些情況,Django 允許你指定一箇中介模型來定義多對多關係。 你可以將其他欄位放在中介模型裡面。原模型的
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),接下來你要開始建立多對多關係。你要做的就是建立中介模型的例項:
>>> 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 = [...])來建立關係:
# 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()方法卻是可用的。它可以清空某個例項所有的多對多關係:
# Beatles have broken up >>> beatles.members.clear() # Note that this deletes the intermediate model instances >>> Membership.objects.all() []