在 Django 中,Model 的繼承方式跟一般 python 的繼承方式大同小異。但是最基礎的 Class 一定要是 django.db.models.Model
,這樣 Django 預設的 Model 行為才能正常運行。
主要要考慮的點只有一個:親層 Model 是否要為資料庫中的一個表,還是它只一個公用的模板,攜帶一些常見的屬性。
Django 官方推薦三種繼承方式:
Abstract base classes
。multi-table inheritance
。這是最像一般 python 繼承的方法。Proxy models
是一個合適的方案。寫法和一般 python 繼承大同小異,只不過需要增加一行設定。主要原因是因為,在 Django 中,只要繼承了 django.db.models.Model
的類別都會被拿來生成相應的表。但如上述,使用 Abstract Base Classes 就是想避免此情況。
from django.db import models
class AbstractModel(models.Model):
name = models.CharField(max_length=50)
def hey(self):
print("hey")
class Meta:
abstract = True
class RealModel(AbstractModel):
pass
r = RealModel.objects.create(name="Duke")
print(r.name) # Duke
r.hey() # hey
test = AbstractModel(name="test")
# TypeError: Abstract models cannot be instantiated.
不但 AbstractModel
不會再資料庫長出一張表來。假設我們強行以他實體化,會發生錯誤的。
這個更簡單了,直接拔掉 abstract = True
即可。和一般 python 繼承無異。
from django.db import models
class AbstractModel(models.Model):
name = models.CharField(max_length=50)
def hey(self):
print("hey")
class RealModel(AbstractModel):
pass
r = RealModel.objects.create(name="Duke")
print(r.name) # Duke
r.hey() # hey
a = AbstractModel.objects.create(name="test")
print(a.name) # test
a.hey() # hey
直得注意的有兩點:
OneToOneField
代表。假設想要更改這個 field 名字的話,可以在子層中自建 OneToOneField
並更改命名。最後,假如你不想創建一個新的表單,只要增加或修改既有模型的方法或是 object manager
。也就說,你只是想改變該模型 Python 上的行為,而不想影響到相連的資料庫表單。這時候只要新增一個子層繼承既有的親層,並在子層加上 proxy=True
即可。
from django.db import models
class BaseModel(models.Model):
name = models.CharField(max_length=50)
def hey(self):
print("hey")
class ProxyModel(BaseModel):
def shout(self);
print(self.name)
def hey(self):
print("heyhey")
b = BaseModel.objects.create(name="Duke")
print(b.name) # Duke
b.shout() # Duke
b.hey() # heyhey
p = ProxyModel.objects.create(name="test")
# TypeError: Proxy models cannot be instantiated.
Proxy Models 本身不能創建物件,但可以覆蓋或增加親層的既有方法。
這種作法對已上線的專案非常實用,因為既不會影響到資料庫的運行,也可以增加開發者使用的自由度。