最近開發的一個項目中用到模型快照剛開始准備用 Django 模型做,於是查看了 Django 模型繼承的幾種方式,由於該項目只是使用 Django 作為後台管理並沒有直接生成遷移文件定義數據庫。最後這些模型繼承方案都未被采用但是這裡還是需要總結記錄。
抽象繼承:創建一個通用的父類,但是我們並不想父類被創建,但是繼承該父類的子類都有該抽象父類的字段。在抽象父類的 Meta 中設置 abstract=true 即可實現。
應用場景舉例:
我們有兩個模型 Book 、Author 這兩個模型我們都需要 createdAt 以及 updatedAt 以及 enable 字段,如果我們每個模型都定義一次這樣會顯得有點冗余,這裡可以采用抽象模型繼承的方式,我們定義一個父類包含 createdAt 以及 updatedAt 以及 enable 字段 Book、Author 這兩個類去繼承該父類即可
from django.db import models
# 定義父類抽象類
class Base(models.Molde):
createdAt = models.BigIntegerField(verbose_name='創建時間')
updatedAt = models.BigIntegerField(verbose_name='更新時間')
enable = models.BooleanField(verbose_name='是否可用')
class Meta:
# 表示該模型為抽象類不會被創建
abstract = True
# 定義子類, 子類中包含父類中的所有屬性以及自身所定義的屬性
class Book(Base):
name = models.CharField(max_length=32)
class Author(Base):
name = models.CharField(max_length=32)
對於多表繼承其父類也是一個 Django 模型,並且父類會創建一個數據表,多表繼承是 Djnago 中一種隱式的一對一的關系:
# 父類
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
# 子類
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
這裡 Restaurant 和 Place 是一對一的關系,當我們在執行 django 生成遷移文件命令時可以看到他們之間的關系。
注意️:使用多表繼承時父類子類必須是使用 django 遷移生成的表,否則無法正常使用表模型
使用代理模式的模型表不會被創建,其實都是指向同一個模型。
from django.db import models
class Person(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=32)
class OrderPerson(Person):
class Meta:
ordering = ['id']
proxy = True
這裡的 OrderPerson 並不會被創建,當我們在修改 OrderPerson 中的數據時對應的 Person 中的數據也會被修改。
注意️:proxy model 不能繼承抽象類,這是因為代理 model 是操作鏈接數據庫的也不能多重繼承,如果你使用了多重繼承 proxy model 就不知道去找那個父親類。
假設我們有如下兩個模型 Book、Author
class Author(models.Model):
id = models.BigAutiField(primary_key=True)
name = models.CharField(max_length=32)
class Book(models.Models):
name = models.CharField(max_lenght=32)
first_author = models.ForeignKey(Author, no_delete=models.CASCADE)
secend_author = models.ForeignKey(Author, no_delete=models.CASCADE)
如上模型定義我們的書籍可能有多個作者,first_author secend_author 都關聯 Author 這張表,如果我們運行該代碼會被錯。
原因:指向一個模型的兩個外鍵反向關聯名稱產生沖突,django 默認情況下對每個主表的對象都有一個外鍵屬性,可以通過它查詢到所有關於子表的信息,這個屬性的名字默認就是子表的名稱小寫加上_set,而 first_author 和 secend_author 該屬性默認都是 book_set,導致沖突,解決辦法:我們可以通過定義 related_name 來手動定義該屬性,正確代碼如下:
class Author(models.Model):
id = models.BigAutiField(primary_key=True)
name = models.CharField(max_length=32)
class Book(models.Models):
name = models.CharField(max_lenght=32)
first_author = models.ForeignKey(Author, no_delete=models.CASCADE, related_name='first_author')
secend_author = models.ForeignKey(Author, no_delete=models.CASCADE, related_name='secend_author')