Как работает Мета-класс Джанго?

191

Я использую Django, который позволяет людям добавлять дополнительные параметры в класс с помощью class Meta.

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

Единственное, что я нашел в документации Python, было:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Однако я не думаю, что это одно и то же.

miki725
источник
6
Название спрашивает о метафоне Python, но кажется, что вопрос о мета Django - какой из них вы спрашиваете?
2012 г.
10
@ckhan он смущен из-за абсурдного решения (IMO) назвать вложенный класс "Meta", что очень вводит в заблуждение; начинающим, о метаклассах Python и более опытным пользователям, которые никогда его не видели, о его назначении априори (вместо использования атрибутов класса или реальных метаклассов)
JC

Ответы:

234

Вы задаете вопрос о двух разных вещах:

  1. Metaвнутренний класс в моделях Django :

    Это просто контейнер класса с некоторыми опциями (метаданными), прикрепленными к модели. Он определяет такие вещи, как доступные разрешения, имя связанной таблицы базы данных, является ли модель абстрактной или нет, единственная и множественная версии имени и т. Д.

    Краткое объяснение здесь: Django docs: Модели: мета-опции

    Список доступных мета-опций находится здесь: Django docs: Model Meta options

    Для последней версии Django: Django docs: Параметры модели Meta

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

    Лучшее описание здесь: что такое метаклассы в Python?

Tadeck
источник
3
Эти две вещи связаны вообще? то есть, Metaвнутренний класс Django мешает вам использовать встроенные в Python функции метакласса?
15:00
10
@nnyby: есть две вещи, которые создают связь между этими двумя понятиями: имя и путаница у многих пользователей (как это было у OP в оригинальном вопросе). Я считаю, что решение этой общей путаницы является существенным преимуществом этих топи. Ты не согласен?
Tadeck
49

Продолжая ответ Тадека на Django выше, использование 'class 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

Вы также можете изучить его непосредственно в 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объектом, созданным моделью metaclassпри ее создании. Здесь вы найдете всю «мета» информацию класса Django. В Django Metaпросто используется для передачи информации в процесс создания _meta Optionsобъекта.

Пол Уипп
источник
Это не работает на пользовательских моделях: >>> из myapp.models import MyModel >>> MyModel.Meta Traceback (последний вызов был последним): файл "<console>", строка 1, в <module> AttributeError: Тип объекта «MyModel» не имеет атрибута «мета»
bdf
2
Вам нужно подчеркнуть, например,MyUser.objects.get(pk=1)._meta
Пол Уипп
Правильно, но это не дает доступа к внутреннему Мета-классу класса Модели. Это обращается к опциям _meta для экземпляра этой Модели ... похоже, нет способа получить доступ к самому внутреннему мета-классу. Вариант использования для меня заключался в создании подкласса прокси-класса MyModelProxy из MyModel таким образом, чтобы MyModelProxy мог наследовать внутренний Meta-класс MyModel.
bdf
Я не совсем ясно , на что вы имеете в виду под «внутренним классом Meta» модели, но вы всегда можете работать непосредственно с экземпляром класса , напримерtype(MyUser.objects.get(pk=1)).Meta
Paul Whipp
3
«удобное пространство имен для общих данных между экземплярами классов». Эта строка сделала это для меня.
MGP
22

ModelКласс Django специально обрабатывает наличие атрибута с именем, Metaкоторый является классом. Это не общая вещь Python.

Метаклассы Python совершенно разные.

янтарный
источник
12
Я думаю, что ваш ответ недостаточно ясен - не могли бы вы рассказать, как Metaработает класс? Я полагаю, что ОП спросил об этом конкретно.
Tadeck
7

Ответы, которые утверждают, что модели Metaи метаклассы Django «абсолютно разные», вводят в заблуждение.

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

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

И одна из вещей, которые ModelBase делает, - это создание _metaатрибута в каждой модели Django, который содержит механизм проверки, подробности поля, логику сохранения и так далее. Во время этой операции материал, указанный во внутреннем Metaклассе модели, читается и используется в этом процессе.

Итак, хотя да, в некотором смысле Metaметаклассы - это разные «вещи», в механике построения модели Джанго они тесно связаны; понимание того, как они работают вместе, углубит ваше понимание обоих.

Это может быть полезным источником информации, чтобы лучше понять, как модели Django используют метаклассы.

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

И это также может помочь, если вы хотите лучше понять, как работают объекты в целом.

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

jhrr
источник
0

Документ внутреннего мета-класса Этот документ метаданных модели django представляет собой «все, что не является полем», такое как параметры упорядочения (упорядочение), имя таблицы базы данных (db_table) или удобочитаемые имена единственного и множественного числа (verbose_name и verbose_name_plural). Ничего не требуется, и добавление класса Meta к модели совершенно необязательно. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
источник
0

В Django он действует как класс конфигурации и хранит данные конфигурации в одном месте!

Риши Чхабра
источник