Django的Meta类如何工作?


189

我正在使用Django,它允许人们使用来向类添加额外的参数class Meta

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

我在Python文档中发现的唯一东西是:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

但是,我认为这不是一回事。


6
Title询问Python meta,但问题似乎询问Django meta-您要问的是哪一个?
ckhan 2012年

10
@ckhan由于将嵌套类称为“ Meta”的荒谬决定(IMO)而感到困惑,这是非常令人误解的;对于Python的元类的初学者以及从未使用过Python的经验丰富的用户,其目的是先验的(而不是使用类属性或真实的元类)
JC Rocamonde

Answers:


231

您在问有关两个不同问题的问题:

  1. MetaDjango模型中的内部类

    这只是一个类容器,在模型上附加了一些选项(元数据)。它定义了诸如可用权限,关联的数据库表名称,模型是否抽象,名称的单复数形式等内容。

    简短说明在这里:Django文档:模型:Meta选项

    可用的元选项列表在此处:Django文档:Model Meta options

    对于最新版本的Django:Django docs:Model Meta options

  2. Python中的元类

    最好的描述在这里:Python中的元类什么?


3
这两件事有关系吗?即,Django的Meta内部类是否阻止您使用Python的内置元类功能?
nnyby 2015年

10
@nnyby:有两个东西在这两个概念之间建立了联系:名称和许多用户感到困惑(就像OP在原始问题中一样)。我相信解决常见的混淆是此topi的重要优势。你不同意吗?
塔德克

49

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

内部类是在类实例之间共享数据的方便的命名空间(因此,名称为“ metadata”的元数据,但是您可以随意命名)。在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中,您更可能希望探索创建模型时由模型创建_metaOptions对象的属性metaclass。在这里,您将找到所有Django类“元”信息。在Django中,Meta仅用于将信息传递到创建_meta Options对象的过程中。


这在用户定义的模型上不起作用:>>>从myapp.models导入MyModel >>> MyModel.Meta回溯(最近一次调用):文件“ <控制台>”,<模块> AttributeError中的第1行:类型对象“ MyModel”没有属性“元”
bdf

2
您需要使用下划线,例如MyUser.objects.get(pk=1)._meta
Paul Whipp 2015年

是的,但这不能访问Model类的内部Meta类。这将访问该Model实例的_meta选项...似乎不是一种访问内部Meta类本身的方法。对我而言,用例是从MyModel继承MyModelProxy的代理MyModelProxy类,而MyModelProxy可以继承MyModel的内部Meta类。
bdf

我对您模型的“内部元类”的含义尚不完全清楚,但您始终可以直接与实例的类一起使用,例如type(MyUser.objects.get(pk=1)).Meta
Paul Whipp 2015年

3
“在类实例之间共享数据的便捷命名空间”这一行为我完成了这一工作。
MGP

22

Django的Model类专门处理具有名为Metawhich 的属性的类。这不是一般的Python。

Python元类完全不同。


12
我认为您的答案不够清楚-您能否详细说明Meta课堂的工作方式?我相信OP对此特别提出了疑问。
塔德克2012年

7

声称Django模型Meta和元类“完全不同”的答案具有误导性。

Django模型类对象(也就是说,代表类定义本身的对象;是的,类也是对象)的构造实际上是由称为的元类控制的ModelBase,您可以在此处看到该代码:

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

要做的事情之一ModelBase就是_meta在每个Django模型上创建属性,该模型包含验证机制,字段详细信息,保存逻辑等。在此操作期间,将Meta在该过程中读取和使用模型的内部类中指定的内容。

因此,虽然是的,Meta但从某种意义上说,元类是不同的“事物”,但在Django模型构建的机制内,它们是密切相关的;了解它们如何协同工作将一次加深您的见解。

这可能是有用的信息来源,可以更好地了解Django模型如何使用元类。

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

如果您想更好地了解对象的总体工作原理,这也可能会有所帮助。

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



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.