1. 程式人生 > >Django - 回顧(2)- 中介模型

Django - 回顧(2)- 中介模型

一、中介模型

  我們之前學習圖書管理系統時,設計了Publish、Book、Author、AuthorDetail這樣幾張表,其中Book表和Author表是多對多關係,處理類似這樣簡單的多對多關係時,使用標準的ManyToManyField就可以了。但是,有時你可能需要關聯資料到兩個模型之間的關係上。

  例如,有這樣一個應用,它記錄音樂家所屬的音樂小組。我們可以用一個ManyToManyField 表示小組和成員之間的多對多關係。但是,有時你可能想知道更多成員關係的細節,比如成員是何時加入小組的。

  對於這些情況,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),接下來你要開始建立多對多關係。你要做的就是建立中介模型的例項:

  >>> 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_joinedinvite_reason);而簡單的add、create 和賦值語句是做不到這一點的。所以它們不能在使用中介模型的多對多關係中使用。此時,唯一的辦法就是建立中介模型的例項。

  remove()方法被禁用也是出於同樣的原因。但是clear()方法卻是可用的。它可以清空某個例項所有的多對多關係:

  # Beatles have broken up
  >>> beatles.members.clear()
  # Note that this deletes the intermediate model instances
  >>> Membership.objects.all()
  []