Як працює мета класу Джанго?


191

Я використовую Django, який дозволяє людям додавати додаткові параметри до класу за допомогою class Meta.

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

Єдине, що я знайшов у документації Python:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Однак я не думаю, що це одне й те саме.


6
Заголовок запитує про мета мета Python, але, здається, питання про мета Джанго - про кого ви питаєте?
ckhan

10
@ckhan він плутається через абсурдне рішення (IMO) називати вкладений клас "Meta", що дуже вводить в оману; для початківців, про метакласи Python, а також для більш досвідчених користувачів, які його ніколи не бачили, про його призначення апріорі (замість використання атрибутів класу чи реальних метакласів)
JC Rocamonde

Відповіді:


233

Ви ставите питання про дві різні речі:

  1. Metaвнутрішній клас у моделях Джанго :

    Це просто контейнер класу з деякими параметрами (метаданими), доданими до моделі. Він визначає такі речі, як доступні дозволи, пов’язане ім'я таблиці бази даних, модель абстрактна чи ні, сингулярна та множинна версії імені тощо.

    Коротке пояснення тут: Документи Django: Моделі: Мета-параметри

    Список доступних мета-опцій тут: Документи Джанго: Моделі мета-параметри

    Для останньої версії Django: Документи Django: Моделі мета-параметри

  2. Метаклас у Python :

    Найкращий опис тут: Що таке метакласи в Python?


3
Чи пов'язані ці дві речі взагалі? тобто, чи не дозволяє Metaвнутрішній клас Джанго використовувати вбудовані функції метакласу Python?
nnyby

10
@nnyby: Є дві речі, які створюють співвідношення між цими двома поняттями: ім'я та плутанина у багатьох користувачів (як це було у ОР в оригінальному питанні). Я вважаю, що вирішення питання про те, що загальна плутанина є суттєвою перевагою цього топі. Ви не згодні?
Тадек

49

Поширюючись на відповідь Джандо Тадека вище, використання "класу Meta:" у Django також є звичайним Python.

Внутрішній клас - це зручний простір імен для спільних даних між екземплярами класу (звідси назва Meta для "метаданих", але ви можете назвати її все, що завгодно). Хоча в 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

Ви також можете досліджувати його в Джанго безпосередньо, наприклад:

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об'єктом, створеним моделлю metaclassпри створенні моделі. Саме тут ви знайдете всю мета-інформацію класу Django. У Django Metaпросто використовується для передачі інформації в процес створення _meta Optionsоб'єкта.


Це не працює на визначених користувачем моделях: >>> з імпорту myapp.models MyModel >>> MyModel.Meta Traceback (останній останній дзвінок): Файл "<console>", рядок 1, в <module> AttributeError: type object 'MyModel' не має атрибута 'meta'
bdf

2
Вам потрібно підкреслити, наприкладMyUser.objects.get(pk=1)._meta
Пол Віпп,

Правильно, але це не має доступу до внутрішнього мета класу класу Model. Це дозволяє отримати доступ до параметрів _meta для екземпляра цієї моделі ... Здається, не існує способу доступу до внутрішнього мета-класу. Випадок використання для мене підкласифікував проксі-клас MyModelProxy від MyModel таким чином, що MyModelProxy може успадкувати внутрішній мета-клас MyModel.
bdf

Мені не зовсім зрозуміло, що ви маєте на увазі під «внутрішнім мета-класом» моделі, але ви завжди можете працювати безпосередньо з класом екземпляра, наприкладtype(MyUser.objects.get(pk=1)).Meta
Пол Віпп

3
"зручний простір імен для спільних даних серед екземплярів класу" Цей рядок зробив це для мене.
MGP

22

ModelКлас Django спеціально обробляє атрибут, Metaякий називається "клас". Це не загальна річ Python.

Метакласи Python абсолютно різні.


12
Я думаю, що ваша відповідь недостатньо чітка - ви могли б детальніше розповісти, як Metaпрацює клас? Я вважаю, що ОП запитала саме про це.
Тадек

7

Відповіді, які стверджують, що моделі Metaі метакласи Джанго є "абсолютно різними", є хибними відповідями.

Побудова об'єктів класу модель Джанго (тобто об'єкт, який позначає саме визначення класу; так, класи також є об'єктами) дійсно контролюється метакласом, який називається ModelBase, цей код ви можете побачити тут:

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

І однією з речей ModelBaseє створення _metaатрибута для кожної моделі Django, яка містить механізм перевірки, деталі поля, збереження логіки тощо. Під час цієї операції матеріали, які вказані у внутрішньому Metaкласі моделі, читаються та використовуються в рамках цього процесу.

Отже, хоча так, у певному сенсі Metaі метакласи - це різні "речі", всередині механіки побудови моделі Джанго вони тісно пов'язані; розуміння того, як вони працюють разом, поглибить ваше розуміння обох відразу.

Це може бути корисним джерелом інформації, щоб краще зрозуміти, як моделі Джанго використовують метакласи.

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

І це також може допомогти, якщо ви хочете краще зрозуміти, як працюють об'єкти взагалі.

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


0

Документ про внутрішній мета-клас Цей документ метаданих моделі django - це "все, що не є полем", такі як параметри впорядкування (замовлення), назва таблиці бази даних (db_table) або особисті і множинні назви, прочитані людиною (verbose_name та verbose_name_plural). Жоден не потрібен, і додавання класу Meta до моделі зовсім необов’язково. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options


0

У Django він виступає як клас конфігурації і зберігає дані конфігурації в одному місці !!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.