2012-04-27 12 views
115

我正在使用Django,它允許人們通過使用class Meta向課程中添加額外的參數。Django的Meta類如何工作?

class FooModel(models.Model): 
    ... 
    class Meta: 
     ... 

我Python的文檔中發現的唯一的事情是:

class FooMetaClass(type): 
    ... 

class FooClass: 
    __metaclass__ = FooMetaClass 

不過,我不認爲這是同樣的事情。

+3

題目問關於Python元,但問題似乎問的Django元 - 你問哪一個? – ckhan 2012-04-27 03:01:53

回答

145

你問一個問題,關於兩個不同的東西:

  1. Meta在Django模型內部類:

    這只是附着在模型的一些選項(元)一類的容器。它定義了這樣的事情可用權限,相關的數據庫表名,模型是否是抽象與否,單數和名字的複數形式等

    簡短的解釋是在這裏:Django docs: Models: Meta options

    的可用元方案清單是在這裏:Django docs: Model Meta options

  2. 元類在Python

    最好的描述是在這裏:What is a metaclass in Python?

+1

這兩件事情有關嗎?即Django的'Meta'內部類是否阻止您使用Python的內置元類功能? – nnyby 2015-03-03 20:00:51

+7

@nnyby:有兩件事情可以在這兩個概念之間建立關係:許多用戶的名字和混淆(就像OP在原始問題中所說的那樣)。我相信解決這個共同的困惑是這個topi的重要優勢。你不同意嗎? – Tadeck 2015-03-03 23:31:31

19

Django的Model類專門處理具有名爲Meta這是一個類的屬性。這不是一般的Python事物。

Python元類是完全不同的。

+11

我想你的答案還不夠清楚 - 你能否詳細說明'Meta'類是如何工作的?我相信OP問具體問題。 – Tadeck 2012-04-27 03:09:13

34

擴展上面的Tadeck的Django答案,在Django中使用'class Meta:'也只是普通的Python。

內部類是一個方便的名稱空間,用於類實例之間的共享數據(因此名稱元數據爲'元數據',但你可以稱它爲任何你喜歡的東西)。雖然在Django它通常只讀配置的東西,沒有什麼可以阻止你改變它:

In [1]: class Foo(object): 
    ...:  class Meta: 
    ...:   metaVal = 1 
    ...:   
In [2]: f1 = Foo() 
In [3]: f2 = Foo() 
In [4]: f1.Meta.metaVal 
Out[4]: 1 
In [5]: f2.Meta.metaVal = 2 
In [6]: f1.Meta.metaVal 
Out[6]: 2 
In [7]: Foo.Meta.metaVal 
Out[7]: 2 

您可以在Django探索它直接過如:

In [1]: from django.contrib.auth.models import User 
In [2]: User.Meta 
Out[2]: django.contrib.auth.models.Meta 
In [3]: User.Meta.__dict__ 
Out[3]: 
{'__doc__': None, 
'__module__': 'django.contrib.auth.models', 
'abstract': False, 
'verbose_name': <django.utils.functional.__proxy__ at 0x26a6610>, 
'verbose_name_plural': <django.utils.functional.__proxy__ at 0x26a6650>} 

但是,在Django你更可能想要探索_meta屬性,該屬性是創建模型時由模型元類創建的Options對象。那就是你可以找到所有的django類'meta'信息的地方。在Django中,Meta僅用於將信息傳遞到創建_meta選項對象的過程中。

+0

這不會對用戶自定義模式工作: >>>從myapp.models導入爲MyModel >>> MyModel.Meta 回溯(最近最後一次通話): 文件 「」,1號線,在 AttributeError:類型對象'MyModel'沒有'meta'屬性 – bdf 2015-12-11 17:58:18

+0

你需要下劃線eg 'MyUser.objects.get(pk = 1)._ meta' – 2015-12-13 18:51:29

+0

正確,但不能訪問模型類的內部Meta類。訪問該模型實例的_meta選項......似乎沒有辦法訪問內部的Meta類本身。我的用例是從MyModel繼承一個代理MyModelProxy類,其方式是MyModelProxy可以繼承MyModel的內部Meta類。 – bdf 2015-12-14 17:17:14

1

聲稱Django模型的Meta和「元類」「完全不同」的答案是誤導性答案。

的Django模型的構建類對象(這是說代表的類定義的對象本身)被稱爲ModelBase元類確實控制,你可以看到,代碼在這裏:

https://github.com/django/django/blob/master/django/db/models/base.py#L61

ModelBase所做的一件事是在每個包含驗證機制,字段細節,節約機器等的Django模型上創建_meta屬性。並且,在此操作過程中,在該過程中讀取並使用模型的內部Meta類中指定的任何內容。

因此,雖然是的,但從某種意義上說,Meta和元類是不同的'事物',在Django模型構建的機制中它們是密切相關的;瞭解他們如何一起工作會加深你對兩者的洞察力。

這可能是一個有用的信息來源,以便更好地理解Django模型如何使用元類。

https://code.djangoproject.com/wiki/DevModelCreation

如果你想更好地瞭解對象一般是如何工作的,這可能也是幫助。

https://docs.python.org/3/reference/datamodel.html