《 Django3.0
文檔》筆記:Models
Django3.0
模型類
模型可以準确且唯一地描述資料,其包含了存儲資料的重要字段。每個模型都是一個
Python
的類,這些模型類繼承自
django.db.models.Model
,模型類的每個屬性都相當于資料庫表的一個字段。一般來說,每個模型類映射一張資料庫表,每個模型類的執行個體代表資料庫表的一行記錄,每個字段映射為資料庫表的一列。通過模型類和
Django
提供的一套資料庫抽象
API
,可以建立、檢索、更新和删除對象。
from django.db import models
class Person(models.Model):
first_name = models.charField(max_length=30)
last_name = models.CharField(max_length=30)
樣例代碼定義了一個
Person
模型類,包含
first_name
和
last_name
兩個字段。根據該模型類可以建立一個如下的資料庫表:
CREATE TABLE myapp_person(
'id' serial NOT NULL PRIMARY KEY,
'first_name' varchar(30) NOT NULL,
'last_name' varchar(30) NOT NULL
);
字段
模型中最重要且唯一必要的是資料庫的字段定義。字段再類屬性中定義。定義字段名時應小心避免使用與模型
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_data = models.DataField()
num_stars = models.IntegerField()
模型類中每一個字段都應該是某個
Field
字段的執行個體,
Django
利用這些字段類來實作以下功能:
- 字段類型用以指定資料庫資料類型(如:
,INTEGER
,VARCHAR
)。TEXT
- 在渲染表單字段時預設使用的
視圖(如:HTML
,<input type='text'>
)。<select>
- 基本的有效性驗證功能,用于
背景和自動生成表單。Django
每一種字段都需要指定一些特定的參數,例如,
CharField
(以及它的子類)需要接收一個
max_length
參數,用于指定資料庫存儲
VARCHAR
資料時用的位元組數。
一些可選的參數是通用的,可以用于任何字段類型,下面介紹一些經常用到的通用參數:
null
如果設定為
True
,當該字段為空時,
Django
會将資料庫中該字段設定為
NULL
,預設為
False
。
blank
如果設定為
True
,則該字段允許為空,預設為
False
。(注意:該選項與
null
不同,
null
選項僅僅是資料庫層面的設定,然而
blank
是涉及表單驗證方面。如果一個字段設定為
blank=True
,在進行表單驗證時,接收的資料該字段值允許為空,而設定為
blank=False
時,不允許為空。
choices
一系列二進制組,用作此字段的選項。如果提供了二進制組,預設表單小部件是一個選擇框,而不是标準文本字段,并将限制給出的選項。一個選項清單:
YEAR_IN_SCHOOL_CHOICES = [
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
]
每個二進制組的第一個值會存儲在資料庫中,而第二個值将隻會用于在表單中顯示。對于一個模型類的執行個體,要擷取該字段二進制組中相對應的第二個值,使用
get_Foo_display()
方法。例如:
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)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
也可以使用枚舉類以簡潔的方式來定義
choices
:
from django.db import models
class Runner(models.Model):
MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
name = models.CharField(max_length=60)
medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)
default
該字段的預設值,可以是一個值或者是個可調用的對象,如果是個可調用對象,每次執行個體化模型時都會調用該對象。
primary_key
如果設定為
True
,将該字段設定為該模式的主鍵。在一個模型類中,如果沒有對任何一個字段設定
primary_key=True
選項,
Django
會自動添加一個
IntegerField
字段,并設定為主鍵。是以可以不手動設定主鍵,也可以手動重寫
Django
預設設定的主鍵。
主鍵字段是隻讀的,如果想修改一個模型類執行個體的主鍵并儲存,等同于建立一個新的模型類執行個體。例如:
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
unique
如果設定為
True
,這個字段的值必須在整個表中保持唯一。
verbose_name
除了
ForeignKey
,
ManyToManyField
和
OneToOneField
,任何字段類型都接收一個可選的位置參數
verbose_name
,如果未指定該參數值,
Django
會自動使用字段的屬性名作為該參數值,并且把下劃線轉換為空格。
在該例中,備注名為
person's first name
:
在該例中,備注名為
first name
:
ForeignKey
,
ManyToManyField
和
OneToOneField
接收的第一個參數為模型的類名,後面可以添加一個
verbose_name
參數:
poll = models.ForeignKey(
poll,
on_delete=models.CASCADE,
verbose_name = "related place",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
慣例是不将
verbose_name
的首字母大寫,必要時
Django
會自動把首字母轉換為大寫。
關聯
顯然,關系型資料庫的強大之處在于各表之間的關聯關系。
Django
提供了定義三種最常見的資料庫關聯關系的方法:多對一,多對多,一對一。
多對一關聯
定義一個多對一的關聯關系,使用
django.db.models.ForeignKey
類,和其他
Field
字段類型一樣,隻需要在模型類中添加一個值為關聯模型類的屬性。
ForeignKey
類需要添加一個位置參數,即想要關聯的模型類名。
例如,一個
Car
模型類有一個制造者
Manufacturer
,一個
Manufacturer
制造許多輛車,但是每輛車都僅有一個制造者,那麼使用下面的方法定義這個關系:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
建議設定
ForeignKey
字段名為想要關聯的模型類名,也可以自定義關聯字段名,例如:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
)
多對多關聯
定義一個多對多的關聯關系,使用
django.db.models.ForeignKey
類,和其他
Field
字段類型一樣,隻需要在模型類中添加一個值為關聯模型類的屬性。
ManyToManyField
類需要添加一個位置參數,即想要關聯的模型類名。
例如,如果
Pizza
含有多種
Topping
(配料),一種
Topping
可能存在于多個
Pizza
中,并且每個
Pizza
含有多種
Topping
,那麼可以表示這種關系:
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
建議設定
ManyToManyField
字段名為一個複數名詞(如
toppings
),表示所要關聯的模型類對象的集合。
注意:對于多對多關聯關系的兩個模型類,可以在任何一個模型類中添加
ManyToManyField
字段,但隻能選擇一個模型類設定該字段,即不能同時在兩模型類中添加該字段。一般情況下,應該把
ManyToManyField
執行個體放到需要在表單中被編輯的對象中。在之前的例子中,
toppings
被放在
Pizza
當中(而不是
Topping
中有指向
Pizza
的
ManyToManyField
執行個體),因為相較于配料被放在不同的披薩當中,披薩當中有很多種配料更加符合常理。按照先前說的,在編輯
Pizza
的表單時使用者可以選擇多種配料。
中介模型
如果隻是想要一個類似于記錄披薩和配料關系之間混合和搭配的多對多關系,标準的
ManyToManyField
就夠用了,但是有時可能需要将資料與兩個模型之間的關系相關聯。
舉例來講,考慮一個需要跟蹤音樂人屬于哪個音樂組的應用程式,在人和他們所在的組之間有一個多對多關系,可以使用
ManyToManyField
來表示這個關系。然而,如果想要記錄更多的資訊在這樣的關聯表當中,比如想要記錄某人是何時加入一個組的。對于這些情況,
Django
允許指定用于控制多對多關系的模型類:可以在中介模型當中添加額外的字段。在執行個體化
ManyToManyField
的時候使用
through
參數指定多對多關系使用哪個中介模型。舉例代碼如下:
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)
通過中介模型完成
ManyToManyField
後,可以通過執行個體化中介模型來建立多對多關系:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles, date_joined=date(1962, 8, 16), invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles, date_joined=date(1960, 8, 1), invite_reason="Wanted to from a band.")
>>> beatles.member.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
如果自定義中介模型沒有強制
(model1, model2)
對的唯一性,調用
remove()
方法會将相關的執行個體都删除,調用
clear()
方法則會删除所有的中介模型執行個體。
>>> Membership.objects.create(person=ringo, group=beatles, date_joined=date(1968, 9, 4), invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
一旦建立了自定義多對多關聯關系,就可以執行查詢操作,和一般的多對多關聯關系一樣,可以使用多對多關聯模型的屬性來查詢:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
# Find all the members of The Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(group__name='The Beatles', membership__date__joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
一對一關聯
使用
OneToOneField
來定義一對一關系,就像使用其他類型的
Field
一樣:在模型屬性中包含它。當一個對象以某種方式“繼承”另一個對象時,這對該對象的主鍵非常有用。
OneToOneField
需要一個位置參數:與模型相關聯的類。
例如,當建立一個有關“位置”資訊的資料庫時,可能會包含通常的位址,電話等字段。接着,如果想要接着建立一個關于“餐廳”的資料庫,除了将位置資料庫當中的字段複制到
Restaurant
模型類,也可以将一個指向
Place
模型類的
OneToOneField
放到
Restaurant
當中(因為“餐廳”是一個“地點”),事實上,在處理這樣的情況下最好使用模型繼承,它隐含的包括了一個一對一關系。和
ForeignKey
一樣,可以建立自關聯關系也可以建立與尚未定義的模型的關系。
OneToOneField
字段還可以接收一個可選的
parent_link
參數。
OneToOneField
類通常自動的成為模型的主鍵,這條規則現在不再使用了(然而可以通過手動指定
primary_key
參數)。是以,可以在單個模型當中指定多個
OneToOneField
字段。
字段命名限制
Django
對模型類的字段名有一些限制:
1.一個字段的名稱不能是
Python
保留字,因為這會導緻
Python
文法錯誤。比如:
class Example(models.Model):
pass = models.IntegerField() # 'pass' is a reserved word!
2.一個字段名稱不能包含連續的多個下劃線,原因在于
Django
查詢文法的工作方式。比如:
class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar has two underscores!'
3.字段名不能以下劃線結尾,原因同上。
SQL
保留字,例如
join
,
where
或
select
,是可以被用在模型字段名當中的,因為
Django
在對底層的
SQL
查詢當中清洗了所有的資料庫表名和字段名,通過使用特定資料庫引擎的引用文法。
Meta
選項
Meta
使用内部
Meta
類來給模型賦予中繼資料,就像:
from django.db import models
class 0x(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
模型的中繼資料即“所有不是字段的東西”,比如排序選項(
oedering
),資料庫表名(
db_table
),或是閱讀友好的單複數名(
verbose_name
和
verbose_name_plural
)。這些都不是必須的,并且在模型當中添加
Meta
類也是完全可選的。
模型屬性
objects
模型當中最重要的屬性是
Manager
,它預設是
Django
模型和資料庫查詢操作之間的接口,并且它被用作從資料庫中擷取執行個體對象,如果沒有指定自定義的
Manager
,預設名稱是
objects
。
Manager
隻能通過模型類來通路,不能通過模型執行個體來通路。
模型方法
在模型方法中添加自定義方法會給你的對象提供自定義的“行級”操作能力,與之對應的是類
Manager
的方法意在提供“表級”的操作,模型方法應該在某個對象執行個體上生效。這是一個将相關邏輯代碼放在一個地方的技巧——模型。比如,該模型有一些自定義方法:
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)
例子中的最後一個方法是
property
,下面介紹兩個最可能期望複寫的:
__str__()
一個
Python
的“魔法方法”,傳回值友好地展示了一個對象。
Python
和
Django
在要将模型執行個體展示為純文字時調用。最有可能的應用場景是互動式控制台或背景。
get_absolute_url()
該方法告訴
Django
如何計算一個對象的
URL
。
Django
在背景接口使用此方法,或任意時間它需要計算一個對象的
URL
。任何需要一個唯一
URL
的對象需要定義此方法。
模型繼承
模型繼承在
Django
中與普通類繼承在
Python
中的工作方式幾乎完全相同,但也應該遵循本頁開頭的内容。這意味着其基類應該繼承自
django.db.models.Model
。
你隻需要決定父類模型是否需要擁有它們的權利(擁有它們的資料表),或者父類僅作為承載僅子類中可見的公共資訊的載體。
Django
有三種可用的繼承風格。
- 常見情況下,僅将父類用于子類公共資訊的載體,因為你不會想在每個子類中把這些代碼都敲代一遍。這樣的父類永遠都不會單獨使用,是以抽象基類是你需要的。
- 若繼承了一個模型(可能來源于其它應用),且想要每個模型都有對應的資料表,請使用多表繼承。
- 最後,若隻想修改模型的
級行為,而不是以任何形式修改模型字段,代理模型是最佳選擇。Python
抽象基類
抽象基類在你要将公共資訊放入很多模型時會很有用。編寫你的基類,并在
Meta
類中填入
abstract=True
。該模型将不會建立任何資料表。當其用作其他模型類的基類時,它的字段會自動添加至子類。舉個例子:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Students(CommonInfo):
home_group = models.CharField(max_length=5)
Student
模型擁有3個字段:
name
,
age
和
home_group
。
CommonInfo
模型不能用作普通的
Django
模型,因為它是一個抽象基類。它不會生成資料表,也沒有管理器,也不能被執行個體化和儲存。從抽象基類繼承來的字段可以被其他字段或值重寫,或用
None
删除。對很多使用者來說,這種繼承可能就是你想要的,它提供了一種在
Python
級抽出公共資訊的方法,但仍會在子類模型中建立資料表。
Meta繼承
當一個抽象基類被建立,
Django
将所有你在基類中申明的
Meta
内部類以屬性的形式提供。若子類未定義自己的
Meta
類,他将會繼承父類的
Meta
類,當然,子類也可直接繼承父類的
Meta
,比如:
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
在安裝
Meta
屬性前,對抽象基類的
Meta
做了一個調整——設定
abstract=False
。這意味着抽象基類的子類不會自動地變成抽象類。當然,你可以繼承一個抽象基類建立另一個抽象基類,隻需記住顯式地設定
abstract=True
。抽象基類的某些
Meta
屬性對子類是沒用的,比如包含
db_table
意味着所有的子類(你并未在子類中指定他們的
Meta
)會使用同一張資料表,這肯定不是我們想要的。
related_name
和
related_query_name
若你在外鍵或者多對多字段使用了
related_name
或
related_query_name
,你必須為該字段提供一個獨一無二的反向名字和查詢名字。這在抽象基類中一般會引發問題,因為基類中的字段都被子類繼承且保持同樣的值(包括
related_name
和
related_query_name
)。為了解決此問題,當你在抽象基類中(也隻能是在抽象基類中)使用了
related_name
和
related_query_name
,部分值需要包含
'%(app_lable)s'
和
'%(class)s'
。
-
用使用了該字段的子類的小寫類名替換。'%(class)s'
-
用小寫的包含子類的應用名替換。每個安裝的應用名必須是唯一的,應用内的每個模型類名也必須是唯一的。是以,替換後的名字也是唯一的。、'%(app_label)s'
舉個例子,有個應有
common/models.py
:
from django.db import models
class Base(models.Model):
m2m = models.ManyToManyField(
OtherModel,
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",
)
class Meta:
abstract = True
class ChildA(Base):
pass
class ChildB(Base):
pass
附帶另一個應用
rare/models.py
:
from common.models import Base
class ChildB(Base):
pass
common.ChildA.m2m
字段的反轉名是
common_childa_related
,反轉查詢名是
common_childas
。
common.ChildB.m2m
字段的反轉名是
common_childb_related
, 反轉查詢名是
common_childbs
。
rare.ChildB.m2m
字段的反轉名是
rare_childb_related
,反轉查詢名是
rare_childbs
。這決定于你如何使用
'%(class)s'
和
'%(app_label)s'
建構關聯名字和關聯查詢名。但是,若你忘了使用它們,
Django
會在你執行系統檢查(或運作
migrate
)時抛出錯誤。
如果你未指定抽象基類中的
related_name
) 屬性,預設的反轉名會是子類名,後接
'_set'
。這名字看起來就像你在子類中定義的一樣。比如,在上述代碼中,若省略了
related_name
) 屬性,
ChildA
的
m2m
字段的反轉名會是
childa_set
,
ChildB
的是
childb_set
。
多表繼承
Django
支援的第二種模型繼承方式是層次結構中的每個模型都是一個單獨的模型。某個模型都指向分離的資料表,且可被獨立查詢和建立。繼承關系介紹了子類和父類之間的連接配接(通過一個自動建立的
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=True)
Place
的所有字段均在
Restaurant
中可用,雖然資料分别存在不同的表中,是以,以下操作均可:
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
若有一個
Place
同時也是
Restaurant
,你可以通過小寫的模型名将
Place
對象轉為
Restaurant
對象。
>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>
然而,若上述例子中的
p
不是 一個
Restaurant
(它僅是個
Place
對象或是其它類的父類),指向
p.restaurant
會抛出一個
Restaurant.DoesNotExist
異常。
Restaurant
中自動建立的連接配接至
Place
的
OneToOneField
看起來像這樣:
place_ptr = models.OneToOneField(
Place, on_delete=models.CASCADE,
parent_link=True,
primary_key=True,
)
你可以在
Restaurant
中重寫該字段,通過申明你自己的
OneToOneField
,并設定
parent_link=True
。
Meta
和多表繼承
多表繼承情況下,子類不會繼承父類的
Meta
。是以的
Meta
類選項已被應用至父類,在子類中再次應用會導緻行為沖突(與抽象基類中應用場景對比,這種情況下,基類并不存在)。故,子類模型無法通路父類的
Meta
類。不過,有限的幾種情況下:若子類未指定
ordering
屬性或
get_latest_by
屬性,子類會從父類繼承這些。
如果父類有排序,而你并不期望子類有排序,你可以顯示的禁止它:
class ChildModel(ParentModel):
# ...
class Meta:
# Remove parent's ordering effect
ordering = []
繼承與反向關系
由于多表繼承使用隐式的
OneToOneField
連接配接子類和父類,是以直接從父類通路子類是可能的,就像上述例子展示的那樣。然而,使用的名字是
ForeignKey
和
ManyToManyField
關系的預設值。如果你在繼承父類模型的子類中添加了這些關聯,你必須指定
related_name
屬性。假如你忘了,
Django
會抛出一個合法性錯誤。
比如,讓我們用上面的
Place
類建立另一個子類,包含一個
ManyToManyField
:
class Supplier(Place):
customers = models.ManyToManyField(Place)
這會導緻以下錯誤:
Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.
HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.
将
related_name
像下面這樣加至
customers
字段能解決此錯誤:
models.ManyToManyField(Place, related_name='provider')
。
代理模型
使用多表繼承時,每個子類模型都會建立一張新表。這一般是期望的行為,因為子類需要一個地方存儲基類中不存在的額外資料字段。不過,有時候你隻想修改模型的
Python
級行為——可能是修改預設管理器,或添加一個方法。
這是代理模型繼承的目的:為原模型建立一個代理。你可以建立、删除和更新代理模型的執行個體,所有的資料都會存儲的像你使用原模型(未代理的)一樣。不同點是你可以修改代理預設的模型排序和預設管理器,而不需要修改原模型。
代理模型就像普通模型一樣申明。你需要告訴
Django
這是一個代理模型,通過将
Meta
類的
proxy
屬性設定為
True
。
例如,假設你想為
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
類與父類
Person
操作同一張資料表。特别提醒,
Person
的執行個體能通過
MyPerson
通路,反之亦然。
>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>
你也可以用代理模型定義模型的另一種不同的預設排序方法。你也許不期望總對
Persion
進行排序,但是在使用代理時,總是依據
'last_name'
屬性進行排序:
class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True
現在,普通的
Person
查詢結果不會被排序,但
OrderdPerson
查詢會按
last_name
排序。