模型是關(guān)于您的數(shù)據(jù)的單一的、確定的信息來(lái)源。它包含您存儲(chǔ)的數(shù)據(jù)的基本字段和行為。通常,每個(gè)模型映射到單個(gè)數(shù)據(jù)庫(kù)表。
基礎(chǔ)知識(shí):
- 每個(gè)模型都是一個(gè) Python 的類(lèi),這些類(lèi)繼承
django.db.models.Model - 模型類(lèi)的每個(gè)屬性都相當(dāng)于一個(gè)數(shù)據(jù)庫(kù)的字段。
- 綜上訴說(shuō),Django 給你一個(gè)自動(dòng)生成訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的 API;請(qǐng)參閱 Making queries。
簡(jiǎn)單的例子
這個(gè)樣例模型定義了一個(gè) Person, 其擁有 first_name 和 last_name:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
firstname 和 lastname 是模型的字段。每個(gè)字段都被指定為class屬性,每個(gè)屬性映射到數(shù)據(jù)庫(kù)列。
上面的Person模型會(huì)創(chuàng)建一個(gè)這樣的數(shù)據(jù)庫(kù)表:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
一些技術(shù)上的說(shuō)明:
- 該表的名稱(chēng) “myapp_person” 是自動(dòng)從某些模型元數(shù)據(jù)中派生出來(lái),但可以被改寫(xiě)。有關(guān)更多詳細(xì)信息,請(qǐng)參閱:表命名。
- 一個(gè)
id字段會(huì)被自動(dòng)添加,但是這種行為可以被改寫(xiě)。請(qǐng)參閱:默認(rèn)主鍵字段。 - The
CREATE TABLESQL in this example is formatted using PostgreSQL syntax, but it's worth noting Django uses SQL tailored to the database backend specified in your settings file.
使用模型
一旦你定義了你的模型,你需要告訴Django你將會(huì)使用這些模型。通過(guò)編輯你的設(shè)置文件和改變 INSTALLED_APPS 設(shè)置來(lái)添加包含你的 models.py 的模塊的名稱(chēng)來(lái)實(shí)現(xiàn)這一點(diǎn)。
例如,如果您的應(yīng)用程序的模型存在于模塊myapp.models(為應(yīng)用程序創(chuàng)建的包結(jié)構(gòu) manage.py startapp 腳本),INSTALLED_APPS** 應(yīng)該閱讀部分內(nèi)容:
INSTALLED_APPS = [
#...
'myapp',
#...
]
當(dāng)你添加新的APP到 INSTALLED_APPS, 去報(bào)先執(zhí)行manage.py migrate,有時(shí)候需要限制性 manage.py makemigrations.
字段
模型中最重要的部分——以及模型中唯一需要的部分——是它定義的數(shù)據(jù)庫(kù)字段列表。字段由class屬性指定。注意不要選擇與模型API沖突的字段名,如clean, save 或者 delete.
例子
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
字段類(lèi)型
模型中的每個(gè)字段都應(yīng)該是適當(dāng)字段類(lèi)的一個(gè)實(shí)例。Django使用field類(lèi)類(lèi)型來(lái)確定一些事情:
- 列類(lèi)型,它告訴數(shù)據(jù)庫(kù)要存儲(chǔ)什么樣的數(shù)據(jù)(例如INTEGER、VARCHAR、TEXT)。
- 默認(rèn)的HTML小部件在呈現(xiàn)表單字段時(shí)使用(例如:<input type="text">,<select>)。
- 在Django的管理員和自動(dòng)生成的表單中使用的最小驗(yàn)證需求。
Django配備了數(shù)十種內(nèi)置的字段類(lèi)型;您可以在模型字段引用中找到完整的列表。如果Django的內(nèi)置函數(shù)不奏效,您可以輕松地編寫(xiě)自己的字段;參見(jiàn)編寫(xiě)定制模型字段。
字段選項(xiàng)
每個(gè)字段都接受一組特定于字段的參數(shù)(在模型字段引用中記錄)。例如,CharField(及其子類(lèi))需要一個(gè) max_length 參數(shù),該參數(shù)指定用于存儲(chǔ)數(shù)據(jù)的VARCHAR 數(shù)據(jù)庫(kù)字段的大小。
對(duì)于所有字段類(lèi)型,也有一組通用的參數(shù)。都是可選的。它們?cè)趨⒖嘉墨I(xiàn)中得到了充分的解釋?zhuān)@里有一個(gè)對(duì)最常用的解釋的快速總結(jié):
null
如果是True,Django會(huì)將空置的值存儲(chǔ)為 NULL。默認(rèn)是False。
blank
如果是True,這個(gè)字段是空白的。默認(rèn)是False。
注意,這與null不同。null與數(shù)據(jù)庫(kù)相關(guān),而blank則是與驗(yàn)證相關(guān)的。如果一個(gè)字段有 blank=True ,表單驗(yàn)證就允許輸入空值。如果一個(gè)字段有blank=False ,則需要字段。
choices
2元組的可迭代(例如,列表或元組),用作此字段的選項(xiàng)。如果給出了這個(gè),則默認(rèn)表單小部件將是一個(gè)選擇框而不是標(biāo)準(zhǔn)文本字段,并將限制對(duì)給定選項(xiàng)的選擇。
選擇列表如下:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
每個(gè)元組中的第一個(gè)元素是儲(chǔ)存在數(shù)據(jù)庫(kù)中的值。第二個(gè)元素由field的form小部件顯示。
給定一個(gè)模型實(shí)例,可以使用 get_FOO_display()方法訪(fǎng)問(wèn)帶有選擇的字段的顯示值。例如:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

如果將models 加載到admin后臺(tái),顯示如下:

default
字段的默認(rèn)值。這可以是一個(gè)值或者一個(gè)可調(diào)用的對(duì)象。如果每次創(chuàng)建新對(duì)象時(shí)都將調(diào)用callable。
help_text
額外的“幫助”文本將顯示在form小部件中。即使你的字段沒(méi)有在表單上使用,它對(duì)文檔也很有用。
name = models.CharField(max_length=60, default=None, help_text="個(gè)人姓名")


primary_key
如果True,此字段是模型的主鍵
如果你沒(méi)有指定你的模型中的任何字段的primarykey=True,Django會(huì)自動(dòng)添加IntegerField來(lái)保存主鍵,所以除非你想要覆蓋默認(rèn)的主鍵行為,否則你不需要在任何字段上設(shè)置primarykey=True。更多信息,請(qǐng)參見(jiàn)自動(dòng)主鍵字段。
主鍵字段是只讀的。如果您將主鍵的值更改為現(xiàn)存對(duì)象,然后保存它,那么將會(huì)在舊物件旁邊創(chuàng)建一個(gè)新物件。例如:
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
unique
如果是真的,這個(gè)字段必須在整個(gè)表中是唯一的。
自動(dòng)主鍵字段
在默認(rèn)情況下,Django提供了以下字段:
id = models.AutoField(primary_key=True)
這是一個(gè)自動(dòng)遞增的主鍵。
如果您想要指定一個(gè)定制的主鍵,請(qǐng)?jiān)谀囊粋€(gè)字段中指定 primarykey=True。如果Django看到你已經(jīng)明確地設(shè)置了字段。主鍵,它不會(huì)添加自動(dòng)id列。
每個(gè)模型只需要一個(gè)字段來(lái)?yè)碛衟rimarykey=True(要么顯式聲明,要么自動(dòng)添加)。
詳細(xì)字段名稱(chēng)
除了和 之外ForeignKey, 每個(gè)字段類(lèi)型都采用可選的第一個(gè)位置參數(shù) - 一個(gè)詳細(xì)的名稱(chēng)。如果沒(méi)有給出詳細(xì)名稱(chēng),Django將使用字段的屬性名稱(chēng)自動(dòng)創(chuàng)建它,將下劃線(xiàn)轉(zhuǎn)換為空格。
ManyToManyFieldOneToOneField
- 在此示例中,詳細(xì)名稱(chēng)為:
"person's first name"
first_name = models.CharField("person's first name", max_length=30)


- 在此示例中,詳細(xì)名稱(chēng)為:"first name"
first_name = models.CharField(max_length=30)
ForeignKey, ManyToManyField and OneToOneField 都要求第一個(gè)參數(shù)是一個(gè)模型類(lèi),所以使用verbosename關(guān)鍵字參數(shù):
poll = models.ForeignKey(
Poll,
on_delete=models.CASCADE,
verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
公約并不是要利用**verbose_name的第一個(gè)字母。Django會(huì)自動(dòng)將第一個(gè)字母大寫(xiě)。
關(guān)聯(lián)關(guān)系
顯然,關(guān)系數(shù)據(jù)庫(kù)的功能在于將表相互關(guān)聯(lián)起來(lái)。Django提供了定義三種最常見(jiàn)的數(shù)據(jù)庫(kù)關(guān)系類(lèi)型的方法:多對(duì)一、多對(duì)多和一對(duì)一。
多對(duì)一
要定義多對(duì)一關(guān)系,請(qǐng)使用django.db.models.ForeignKey。您可以像使用任何其他Field類(lèi)型一樣使用它:將其包含為模型的類(lèi)屬性。
ForeignKey 需要一個(gè)位置參數(shù):模型相關(guān)的類(lèi)。
例如,如果一個(gè)“汽車(chē)”模型有一個(gè)“制造商”——也就是說(shuō),“制造商”生產(chǎn)多輛汽車(chē),但每輛車(chē)都只有一個(gè)“制造商”——使用以下定義:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
多對(duì)多
要定義多對(duì)多關(guān)系,請(qǐng)使用 ManyToManyField。您可以像使用任何其他Field類(lèi)型一樣使用它 :將其包含為模型的類(lèi)屬性。
ManyToManyField 需要一個(gè)位置參數(shù):模型相關(guān)的類(lèi)。
例如,如果一個(gè)“pizza”有多個(gè)“topping”的對(duì)象——也就是說(shuō),“topping”可以在多個(gè)pizza上,每個(gè)“pizza”都有多種topping——以下是你如何表示:
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)</pre>
多對(duì)多關(guān)系中的額外字段
當(dāng)您只處理簡(jiǎn)單的多對(duì)多關(guān)系時(shí),例如混合和匹配比薩餅和澆頭,ManyToManyField您只需要一個(gè)標(biāo)準(zhǔn) 。但是,有時(shí)您可能需要將數(shù)據(jù)與兩個(gè)模型之間的關(guān)系相關(guān)聯(lián)。
例如,考慮應(yīng)用程序跟蹤音樂(lè)家所屬的音樂(lè)組的情況。一個(gè)人與他們所屬的團(tuán)體之間存在多對(duì)多的關(guān)系,因此您可以使用aManyToManyField來(lái)表示這種關(guān)系。但是,您可能希望收集的成員資格有很多詳細(xì)信息,例如此人加入該組的日期。
對(duì)于這些情況,Django允許您指定將用于管理多對(duì)多關(guān)系的模型。然后,您可以在中間模型上添加額外的字段。中間模型與ManyToManyField使用 through參數(shù)指向?qū)⒊洚?dāng)中介的模型相關(guān)聯(lián) 。對(duì)于我們的音樂(lè)家示例,代碼看起來(lái)像這樣:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
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)
設(shè)置中間模型時(shí),您明確指定多對(duì)多關(guān)系中涉及的模型的外鍵。此顯式聲明定義了兩個(gè)模型的關(guān)聯(lián)方式。
中間模型有一些限制:
- 您的中間模型必須包含一個(gè) - 且只有一個(gè) - 源模型的外鍵(這將
Group在我們的示例中),或者您必須顯式指定Django應(yīng)該用于關(guān)系的外鍵ManyToManyField.through_fields。如果您有多個(gè)外鍵through_fields但未指定,則會(huì)引發(fā)驗(yàn)證錯(cuò)誤。類(lèi)似的限制適用于目標(biāo)模型的外鍵(這將Person在我們的示例中)。 - 對(duì)于通過(guò)中間模型與自身具有多對(duì)多關(guān)系的模型,允許同一模型的兩個(gè)外鍵,但它們將被視為多對(duì)多關(guān)系的兩個(gè)(不同)側(cè)。如果有更多的比兩個(gè)外鍵雖然,你還必須指定
through_fields如上,或驗(yàn)證錯(cuò)誤將得到提升。 - 在使用中間模型定義從模型到自身的多對(duì)多關(guān)系時(shí),必須使用
symmetrical=False(請(qǐng)參閱 模型字段引用)。
現(xiàn)在您已經(jīng)設(shè)置了ManyToManyField使用中間模型(Membership在本例中),您已準(zhǔn)備好開(kāi)始創(chuàng)建一些多對(duì)多關(guān)系。您可以通過(guò)創(chuàng)建中間模型的實(shí)例來(lái)完成此操作:

一對(duì)一
定義一對(duì)一, use OneToOneField. 您可以像任何其他“字段”類(lèi)型一樣使用它:將其包含為模型的類(lèi)屬性。
當(dāng)該對(duì)象以某種方式“擴(kuò)展”另一個(gè)對(duì)象時(shí),這在對(duì)象的主鍵上是最有用的。
OneToOneField 需要一個(gè)位置參數(shù):模型相關(guān)的類(lèi)。
例如,如果您正在構(gòu)建“地點(diǎn)”數(shù)據(jù)庫(kù),您將在數(shù)據(jù)庫(kù)中構(gòu)建非常標(biāo)準(zhǔn)的內(nèi)容,例如地址,電話(huà)號(hào)碼等。然后,如果你想在這些地方建立一個(gè)餐館數(shù)據(jù)庫(kù),而不是重復(fù)自己并在Restaurant模型中復(fù)制這些字段,你可以做Restaurant一個(gè)OneToOneFieldto Place(因?yàn)橐粋€(gè)餐館“是一個(gè)”地方;事實(shí)上,處理這通常使用 繼承,它涉及隱式的一對(duì)一關(guān)系)。
與此同時(shí)ForeignKey,可以定義遞歸關(guān)系,并且可以對(duì)尚未定義的模型進(jìn)行引用。
跨文件的模型
將模型與另一個(gè)應(yīng)用程序中的模型相關(guān)聯(lián)是完全可以的。為此,請(qǐng)?jiān)诙x模型的文件頂部導(dǎo)入相關(guān)模型。然后,只需在需要的地方引用其他模型類(lèi)。例如:
from django.db import models
from geography.models import ZipCode
class Restaurant(models.Model):
# ...
zip_code = models.ForeignKey(
ZipCode,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
字段名稱(chēng)限制
jango對(duì)模型字段名稱(chēng)只有兩個(gè)限制:
-
字段名稱(chēng)不能是Python保留字,因?yàn)檫@會(huì)導(dǎo)致Python語(yǔ)法錯(cuò)誤。例如:
class Example(models.Model): pass = models.IntegerField() # 'pass' is a reserved word! -
由于Django的查詢(xún)查找語(yǔ)法的工作方式,字段名稱(chēng)不能在一行中包含多個(gè)下劃線(xiàn)。例如:
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
但是,這些限制可以解決,因?yàn)槟淖侄蚊Q(chēng)不一定必須與您的數(shù)據(jù)庫(kù)列名稱(chēng)匹配。請(qǐng)參閱 db_column選項(xiàng)。
SQL保留字(例如join,where或select)被允許作為模型字段名稱(chēng),因?yàn)镈jango會(huì)轉(zhuǎn)義每個(gè)基礎(chǔ)SQL查詢(xún)中的所有數(shù)據(jù)庫(kù)表名和列名。它使用特定數(shù)據(jù)庫(kù)引擎的引用語(yǔ)法。
Meta選項(xiàng)
使用內(nèi)部提供模型元數(shù)據(jù),如下所示:class Meta
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
模型元數(shù)據(jù)是“任何不是字段的東西”,例如排序選項(xiàng)(ordering),數(shù)據(jù)庫(kù)表名(db_table)或人類(lèi)可讀的單數(shù)和復(fù)數(shù)名稱(chēng)(verbose_name和 verbose_name_plural)。不需要,添加到模型是完全可選的。class Meta
Meta可以在模型選項(xiàng)參考中找到所有可能選項(xiàng)的完整列表。
模型屬性
objects
模型最重要的屬性是 Manager。它是為Django模型提供數(shù)據(jù)庫(kù)查詢(xún)操作的接口,用于 從數(shù)據(jù)庫(kù)中檢索實(shí)例。如果Manager未定義自定義,則默認(rèn)名稱(chēng)為 objects。管理員只能通過(guò)模型??類(lèi)訪(fǎng)問(wèn),而不能通過(guò)模型??實(shí)例訪(fǎng)問(wèn)。
模型方法
在模型上定義自定義方法,以向?qū)ο筇砑幼远x“行級(jí)”功能。雖然Manager方法旨在執(zhí)行“表格范圍”的事情,但模型方法應(yīng)該作用于特定的模型實(shí)例。
這是將業(yè)務(wù)邏輯保存在一個(gè)地方的有價(jià)值的技術(shù) - 模型
例如,此模型有一些自定義方法:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
elif self.birth_date < datetime.date(1965, 1, 1):
return "Baby boomer"
else:
return "Post-boomer"
@property
def full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
此示例中的最后一個(gè)方法是屬性。
該模型實(shí)例參考具有的完整列表,自動(dòng)給每個(gè)模型的方法。您可以覆蓋其中的大多數(shù) - 請(qǐng)參閱下面的覆蓋預(yù)定義模型方法 - 但有幾個(gè)您幾乎總是想要定義:
Python“魔術(shù)方法”,返回任何對(duì)象的字符串表示形式。這是Python和Django在模型實(shí)例需要被強(qiáng)制并顯示為純字符串時(shí)將使用的內(nèi)容。最值得注意的是,當(dāng)您在交互式控制臺(tái)或管理員中顯示對(duì)象時(shí)會(huì)發(fā)生這種情況。
你總是想要定義這個(gè)方法; 默認(rèn)情況下根本沒(méi)有用。
這告訴Django如何計(jì)算對(duì)象的URL。Django在其管理界面中使用它,并且只要它需要找出對(duì)象的URL。
具有唯一標(biāo)識(shí)它的URL的任何對(duì)象都應(yīng)定義此方法。
繼承模型
模型繼承在Django中與普通類(lèi)繼承在Python中的工作方式幾乎完全相同,但也仍有遵循本頁(yè)開(kāi)頭的內(nèi)容。這意味著其基類(lèi)應(yīng)該繼承自django.db.models.Model。
您必須做出的唯一決定是您是希望父模型本身是模型(使用自己的數(shù)據(jù)庫(kù)表),還是父母只是通過(guò)子模型可見(jiàn)的公共信息的持有者。
Django中有三種可能的繼承方式。
- 通常,您只想使用父類(lèi)來(lái)保存您不希望為每個(gè)子模型鍵入的信息。這個(gè)類(lèi)不會(huì)被孤立使用,所以抽象基類(lèi)就是你所追求的。
- 如果你是現(xiàn)有模型的子類(lèi)(可能是完全來(lái)自另一個(gè)應(yīng)用程序的東西),并希望每個(gè)模型都有自己的數(shù)據(jù)庫(kù)表,那么 多表繼承是最佳選擇。
- 最后,如果您只想修改模型的Python級(jí)行為,而不以任何方式更改模型字段,則可以使用 代理模型。
抽象基類(lèi)
當(dāng)您想要將一些公共信息放入許多其他模型時(shí),抽象基類(lèi)非常有用。你寫(xiě)你的基類(lèi),并把abstract=True在元 類(lèi)。然后,此模型將不用于創(chuàng)建任何數(shù)據(jù)庫(kù)表。相反,當(dāng)它用作其他模型的基類(lèi)時(shí),其字段將添加到子類(lèi)的字段中。
一個(gè)例子:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
該Student模型將有三個(gè)領(lǐng)域:name,age和 home_group。該CommonInfo模型不能用作普通的Django模型,因?yàn)樗且粋€(gè)抽象基類(lèi)。它不生成數(shù)據(jù)庫(kù)表或具有管理器,并且無(wú)法直接實(shí)例化或保存。
從抽象基類(lèi)繼承的字段可以使用其他字段或值覆蓋,也可以使用刪除None。
對(duì)于許多用途,這種類(lèi)型的模型繼承將完全符合您的要求。它提供了一種在Python級(jí)別分解公共信息的方法,同時(shí)仍然只在數(shù)據(jù)庫(kù)級(jí)別為每個(gè)子模型創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)表。
Meta繼承
當(dāng)創(chuàng)建抽象基類(lèi)時(shí),Django使 您在基類(lèi)中聲明的任何Meta內(nèi)部類(lèi)可用作屬性。如果子類(lèi)沒(méi)有聲明自己的Meta 類(lèi),它將繼承父類(lèi)的Meta。如果孩子想要擴(kuò)展父類(lèi)的Meta類(lèi),它可以將其子類(lèi)化。例如:
from django.db import models
class CommonInfo(models.Model):
# ...
class Meta:
abstract = True
ordering = ['name']
class Student(CommonInfo):
# ...
class Meta(CommonInfo.Meta):
db_table = 'student_info'
Django確實(shí)對(duì)抽象基類(lèi)的Meta類(lèi)進(jìn)行了一次調(diào)整:在安裝Meta屬性之前,它設(shè)置了abstract=False。這意味著抽象基類(lèi)的子項(xiàng)本身不會(huì)自動(dòng)成為抽象類(lèi)。當(dāng)然,您可以創(chuàng)建一個(gè)繼承自另一個(gè)抽象基類(lèi)的抽象基類(lèi)。您只需要記住abstract=True每次都明確設(shè)置。
在抽象基類(lèi)的Meta類(lèi)中包含一些屬性是沒(méi)有意義的。例如,包含db_table意味著所有子類(lèi)(未指定自己的Meta)將使用相同的數(shù)據(jù)庫(kù)表,這幾乎肯定不是您想要的。
多表繼承
Django支持的第二種模型繼承是當(dāng)層次結(jié)構(gòu)中的每個(gè)模型都是模型本身時(shí)。每個(gè)模型對(duì)應(yīng)于自己的數(shù)據(jù)庫(kù)表,可以單獨(dú)查詢(xún)和創(chuàng)建。繼承關(guān)系引入子模型與其每個(gè)父模型之間的鏈接(通過(guò)自動(dòng)創(chuàng)建OneToOneField)。例如:
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
盡管數(shù)據(jù)將駐留在不同的數(shù)據(jù)庫(kù)表 Place中 Restaurant,但所有字段都將可用。所以這些都是可能的:
Place.objects.filter(name="Bob's Cafe")
Restaurant.objects.filter(name="Bob's Cafe")
如果你的a Place 也是a Restaurant,你可以使用模型名稱(chēng)的小寫(xiě)版本從 Place對(duì)象到Restaurant對(duì)象:

但是,如果p在上面的示例中不是 a Restaurant(它已直接創(chuàng)建為Place對(duì)象或是其他類(lèi)的父級(jí)),則引用p.restaurant會(huì)引發(fā)Restaurant.DoesNotExist 異常。
自動(dòng)創(chuàng)建OneToOneField的 Restaurant,它鏈接到Place看起來(lái)像這樣:
place_ptr = models.OneToOneField(
Place, on_delete=models.CASCADE,
parent_link=True,
)
Meta和多表繼承
在多表繼承情況下,子類(lèi)從其父類(lèi)的Meta類(lèi)繼承是沒(méi)有意義的。所有的Meta選項(xiàng)都已經(jīng)應(yīng)用于父類(lèi),并且再次應(yīng)用它們通常只會(huì)導(dǎo)致矛盾的行為(這與基類(lèi)本身不存在的抽象基類(lèi)情況形成對(duì)比)。
因此,子模型無(wú)法訪(fǎng)問(wèn)其父級(jí)的Meta類(lèi)。但是,有一些有限的情況,子進(jìn)程從父進(jìn)程繼承行為:如果子進(jìn)程沒(méi)有指定 ordering屬性或get_latest_by屬性,它將從其父進(jìn)程繼承它們。
如果父級(jí)有一個(gè)排序而你不希望孩子有任何自然順序,你可以明確地禁用它:
class ChildModel(ParentModel):
# ...
class Meta:
# Remove parent's ordering effect
ordering = []
代理模型
使用多表繼承時(shí),會(huì)為模型的每個(gè)子類(lèi)創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)表。這通常是所需的行為,因?yàn)樽宇?lèi)需要一個(gè)位置來(lái)存儲(chǔ)基類(lèi)上不存在的任何其他數(shù)據(jù)字段。但是,有時(shí)您只想更改模型的Python行為 - 可能更改默認(rèn)管理器或添加新方法。
這就是代理模型繼承的用途:為原始模型創(chuàng)建代理。您可以創(chuàng)建,刪除和更新代理模型的實(shí)例,并且將保存所有數(shù)據(jù),就像使用原始(非代理)模型一樣。不同之處在于您可以更改代理中的默認(rèn)模型排序或默認(rèn)管理器等內(nèi)容,而無(wú)需更改原始內(nèi)容。
代理模型聲明為普通模型。你通過(guò)設(shè)置類(lèi)的proxy屬性告訴Django它是一個(gè)代理模型。
例如,假設(shè)您要向Person模型添加方法。你可以這樣做:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
該MyPerson班在同一個(gè)數(shù)據(jù)庫(kù)表作為它的父工作 Person類(lèi)。特別是,任何新的實(shí)例 Person 也可以通過(guò) MyPerson,反之亦然:

你仍然可以使用一個(gè)代理模型來(lái)定義模型的默認(rèn)排序方法,你也許不會(huì)想一直對(duì)“Person”進(jìn)行排序,但是通常情況下用代理模型根據(jù)“姓氏”屬性進(jìn)行排序這很簡(jiǎn)單。:
class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True
基類(lèi)限制
一個(gè)代理模型必須僅能繼承一個(gè)非抽象模型類(lèi)。你不能繼承多個(gè)非抽象模型類(lèi),因?yàn)榇砟P蜔o(wú)法提供不同數(shù)據(jù)表的任何行間連接。一個(gè)代理模型可以繼承任意數(shù)量的抽象模型類(lèi),假如他們沒(méi)有定義任何的模型字段。一個(gè)代理模型也可以繼承任意數(shù)量的代理模型,只需他們共享同一個(gè)非抽象父類(lèi)
模型代理管理器
如果未在代理模型上指定任何模型管理器,它將從其模型父項(xiàng)繼承管理器。如果您在代理模型上定義管理器,它將成為默認(rèn)管理器,盡管在父類(lèi)上定義的任何管理器仍然可用。
繼續(xù)上面的示例,您可以更改查詢(xún)Person模型時(shí)使用的默認(rèn)管理器,如下所示:
from django.db import models
class NewManager(models.Manager):
# ...
pass
class MyPerson(Person):
objects = NewManager()
class Meta:
proxy = True
如果要在不更換現(xiàn)有默認(rèn)值的情況下向代理添加新管理器,可以使用自定義管理器文檔中描述的技術(shù):創(chuàng)建包含新管理器的基類(lèi),并在主基類(lèi)之后繼承:
# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
secondary = NewManager()
class Meta:
abstract = True
class MyPerson(Person, ExtraManagers):
class Meta:
proxy = True
多重繼承
正如Python的子類(lèi)化一樣,Django模型可以從多個(gè)父模型繼承。請(qǐng)記住,正常的Python名稱(chēng)解析規(guī)則適用。特定名稱(chēng)(例如Meta)出現(xiàn)的第一個(gè)基類(lèi)將是使用的基類(lèi); 例如,這意味著如果多個(gè)父類(lèi)包含一個(gè)Meta類(lèi),則只會(huì)使用第一個(gè)類(lèi),而將忽略所有其他類(lèi)。
通常,您不需要從多個(gè)父級(jí)繼承。這有用的主要用例是“混入”類(lèi):向每個(gè)繼承混合的類(lèi)添加特定的額外字段或方法。盡量使您的繼承層次結(jié)構(gòu)盡可能簡(jiǎn)單明了,這樣您就不必費(fèi)力去找出特定信息來(lái)自哪里。
請(qǐng)注意,從具有公共id主鍵字段的多個(gè)模型繼承將引發(fā)錯(cuò)誤。要正確使用多重繼承,可以AutoField在基本模型中使用explici
class Article(models.Model):
article_id = models.AutoField(primary_key=True)
...
class Book(models.Model):
book_id = models.AutoField(primary_key=True)
...
class BookReview(Book, Article):
pass