該系列教程系個人原創,並完整發佈在個人官網 "劉江的博客和教程" 所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。 Python及Django學習QQ群:453131687 模型的元數據,指的是“除了欄位外的所有內容”,例如排序方式、資料庫表名、人類可讀 ...
該系列教程系個人原創,並完整發佈在個人官網劉江的博客和教程
所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。
Python及Django學習QQ群:453131687
模型的元數據,指的是“除了欄位外的所有內容”,例如排序方式、資料庫表名、人類可讀的單數或者複數名等等。所有的這些都是非必須的,甚至元數據本身對模型也是非必須的。但是,我要說但是,有些元數據選項能給予你極大的幫助,在實際使用中具有重要的作用,是實際應用的‘必須’。
想在模型中增加元數據,方法很簡單,在模型類中添加一個子類,名字是固定的Meta
,然後在這個Meta類下麵增加各種元數據選項或者說設置項。參考下麵的例子:
from django.db import models
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta: # 註意,是模型的子類,要縮進!
ordering = ["horn_length"]
verbose_name_plural = "oxen"
上面的例子中,我們為模型Ox增加了兩個元數據‘ordering’和‘verbose_name_plural’,分別表示排序和複數名,下麵我們會詳細介紹有哪些可用的元數據選項。
強調:每個模型都可以有自己的元數據類,每個元數據類也只對自己所在模型起作用。
abstract
如果abstract=True
,那麼模型會被認為是一個抽象模型。抽象模型本身不實際生成資料庫表,而是作為其它模型的父類,被繼承使用。具體內容可以參考Django模型的繼承。
app_label
如果定義了模型的app沒有在INSTALLED_APPS
中註冊,則必須通過此元選項聲明它屬於哪個app,例如:
app_label = 'myapp'
base_manager_name
自定義模型的_base_manager
管理器的名字。模型管理器是Django為模型提供的API所在。Django1.10新增。
db_table
指定在資料庫中,當前模型生成的數據表的表名。比如:
db_table = 'my_freinds'
友情建議:使用MySQL資料庫時,db_table
用小寫英文。
db_tablespace
自定義資料庫表空間的名字。預設值是工程的DEFAULT_TABLESPACE
設置。
default_manager_name
自定義模型的_default_manager
管理器的名字。Django1.10新增。
default_related_name
預設情況下,從一個模型反向關聯設置有關係欄位的源模型,我們使用<model_name>_set
,也就是源模型的名字+下劃線+set
。
這個元數據選項可以讓你自定義反向關係名,同時也影響反向查詢關係名!看下麵的例子:
from django.db import models
class Foo(models.Model):
pass
class Bar(models.Model):
foo = models.ForeignKey(Foo)
class Meta:
default_related_name = 'bars' # 關鍵在這裡
具體的使用差別如下:
>>> bar = Bar.objects.get(pk=1)
>>> # 不能再使用"bar"作為反向查詢的關鍵字了。
>>> Foo.objects.get(bar=bar)
>>> # 而要使用你自己定義的"bars"了。
>>> Foo.objects.get(bars=bar)
get_latest_by
Django管理器給我們提供有latest()和earliest()方法,分別表示獲取最近一個和最前一個數據對象。但是,如何來判斷最近一個和最前面一個呢?也就是根據什麼來排序呢?
get_latest_by
元數據選項幫你解決這個問題,它可以指定一個類似 DateField
、DateTimeField
或者IntegerField
這種可以排序的欄位,作為latest()和earliest()方法的排序依據,從而得出最近一個或最前面一個對象。例如:
get_latest_by = "order_date"
managed
該元數據預設值為True,表示Django將按照既定的規則,管理資料庫表的生命周期。
如果設置為False,將不會針對當前模型創建和刪除資料庫表。在某些場景下,這可能有用,但更多時候,你可以忘記該選項。
order_with_respect_to
這個選項不好理解。其用途是根據指定的欄位進行排序,通常用於關係欄位。看下麵的例子:
from django.db import models
class Question(models.Model):
text = models.TextField()
# ...
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
# ...
class Meta:
order_with_respect_to = 'question'
上面在Answer模型中設置了order_with_respect_to = 'question'
,這樣的話,Django會自動提供兩個API,get_RELATED_order()
和set_RELATED_order()
,其中的RELATED
用小寫的模型名代替。假設現在有一個Question對象,它關聯著多個Answer對象,下麵的操作返回包含關聯的Anser對象的主鍵的列表[1,2,3]:
>>> question = Question.objects.get(id=1)
>>> question.get_answer_order()
[1, 2, 3]
我們可以通過set_RELATED_order()
方法,指定上面這個列表的順序:
>>> question.set_answer_order([3, 1, 2])
同樣的,關聯的對象也獲得了兩個方法get_next_in_order()
和get_previous_in_order()
,用於通過特定的順序訪問對象,如下所示:
>>> answer = Answer.objects.get(id=2)
>>> answer.get_next_in_order()
<Answer: 3>
>>> answer.get_previous_in_order()
<Answer: 1>
這個元數據的作用......還沒用過,囧。
ordering
最常用的元數據之一了!
用於指定該模型生成的所有對象的排序方式,接收一個欄位名組成的元組或列表。預設按升序排列,如果在欄位名前加上字元“-”則表示按降序排列,如果使用字元問號“?”表示隨機排列。請看下麵的例子:
ordering = ['pub_date'] # 表示按'pub_date'欄位進行升序排列
ordering = ['-pub_date'] # 表示按'pub_date'欄位進行降序排列
ordering = ['-pub_date', 'author'] # 表示先按'pub_date'欄位進行降序排列,再按`author`欄位進行升序排列。
permissions
該元數據用於當創建對象時增加額外的許可權。它接收一個所有元素都是二元元組的列表或元組,每個元素都是(許可權代碼, 直觀的許可權名稱)
的格式。比如下麵的例子:
permissions = (("can_deliver_pizzas", "可以送披薩"),)
default_permissions
Django預設給所有的模型設置('add', 'change', 'delete')的許可權,也就是增刪改。你可以自定義這個選項,比如設置為一個空列表,表示你不需要預設的許可權,但是這一操作必須在執行migrate命令之前。
proxy
如果設置了proxy = True
,表示使用代理模式的模型繼承方式。具體內容與abstract選項一樣,參考模型繼承章節。
required_db_features
聲明模型依賴的資料庫功能。比如['gis_enabled'],表示模型的建立依賴GIS功能。
required_db_vendor
聲明模型支持的資料庫。Django預設支持sqlite, postgresql, mysql, oracle
。
select_on_save
決定是否使用1.6版本之前的django.db.models.Model.save()
演算法保存對象。預設值為False。這個選項我們通常不用關心。
indexes
Django1.11新增的選項。
接收一個應用在當前模型上的索引列表,如下例所示:
from django.db import models
class Customer(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Meta:
indexes = [
models.Index(fields=['last_name', 'first_name']),
models.Index(fields=['first_name'], name='first_name_idx'),
]
unique_together
這個元數據是非常重要的一個!它等同於資料庫的聯合約束!
舉個例子,假設有一張用戶表,保存有用戶的姓名、出生日期、性別和籍貫等等信息。要求是所有的用戶唯一不重覆,可現在有好幾個叫“張偉”的,如何區別它們呢?(不要和我說主鍵唯一,這裡討論的不是這個問題)
我們可以設置不能有兩個用戶在同一個地方同一時刻出生並且都叫“張偉”,使用這種聯合約束,保證資料庫能不能重覆添加用戶(也不要和我談小概率問題)。在Django的模型中,如何實現這種約束呢?
使用unique_together
,也就是聯合唯一!
比如:
unique_together = (('name', 'birth_day', 'address'),)
這樣,哪怕有兩個在同一天出生的張偉,但他們的籍貫不同,也就是兩個不同的用戶。一旦三者都相同,則會被Django拒絕創建。這一元數據經常被用在admin後臺,並且強制應用於資料庫層面。
unique_together接收一個二維的元組((xx,xx,xx,...),(),(),()...),每一個元素都是一個元組,表示一組聯合唯一約束,可以同時設置多組約束。為了方便,對於只有一組約束的情況下,可以簡單地使用一維元素,例如:
unique_together = ('name', 'birth_day', 'address')
聯合唯一無法作用於普通的多對多欄位。
index_together
即將廢棄,使用index
元數據代替。
verbose_name
最常用的元數據之一!用於設置模型對象的直觀、人類可讀的名稱。可以用中文。例如:
verbose_name = "story"
verbose_name = "披薩"
如果你不指定它,那麼Django會使用小寫的模型名作為預設值。
verbose_name_plural
英語有單數和複數形式。這個就是模型對象的複數名,比如“apples”。因為我們中文通常不區分單複數,所以保持和verbose_name
一致也可以。
verbose_name_plural = "stories"
verbose_name_plural = "披薩"
如果不指定該選項,那麼預設的複數名字是verbose_name
加上‘s’
label
前面介紹的元數據都是可修改和設置的,但還有兩個只讀的元數據,label就是其中之一。
label等同於app_label.object_name
。例如polls.Question
,polls是應用名,Question是模型名。
label_lower
同上,不過是小寫的模型名。