1. 程式人生 > >模型的元資料Meta -- Django從入門到精通系列教程

模型的元資料Meta -- Django從入門到精通系列教程

該系列教程繫個人原創,並完整發布在個人官網劉江的部落格和教程

所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。

模型的元資料,指的是“除了欄位外的所有內容”,例如排序方式、資料庫表名、人類可讀的單數或者複數名等等。所有的這些都是非必須的,甚至元資料本身對模型也是非必須的。但是,我要說但是,有些元資料選項能給予你極大的幫助,在實際使用中具有重要的作用,是實際應用的‘必須’。

想在模型中增加元資料,方法很簡單,在模型類中新增一個子類,名字是固定的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新增。

預設情況下,從一個模型反向關聯設定有關係欄位的源模型,我們使用<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元資料選項幫你解決這個問題,它可以指定一個類似 DateFieldDateTimeField或者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

同上,不過是小寫的模型名。