模型的元數據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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM