Como funciona a classe Meta do Django?

189

Estou usando o Django, que permite que as pessoas adicionem parâmetros extras a uma classe usando class Meta.

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

A única coisa que encontrei na documentação do Python foi:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

No entanto, acho que não é a mesma coisa.

miki725
fonte
6
O título pergunta sobre a meta do Python, mas a pergunta parece perguntar sobre a meta do Django - qual você está perguntando?
ckhan
10
@ckhan ele está confuso devido à decisão absurda (IMO) de chamar uma classe aninhada "Meta", o que é muito enganador; para iniciantes, sobre metaclasses do Python, e para usuários mais experientes que nunca viram isso, sobre seu propósito a priori (em vez de usar atributos de classe ou metaclasses reais)
JC Rocamonde

Respostas:

231

Você está fazendo uma pergunta sobre duas coisas diferentes:

  1. Meta classe interna nos modelos Django :

    Este é apenas um contêiner de classe com algumas opções (metadados) anexadas ao modelo. Ele define itens como permissões disponíveis, nome da tabela de banco de dados associado, se o modelo é abstrato ou não, versões singular e plural do nome etc.

    Aqui está uma breve explicação: Django docs: Models: Meta options

    A lista de meta opções disponíveis está aqui: Django docs: Model Meta options

    Para a versão mais recente do Django: Django docs: opções do Model Meta

  2. Metaclasse em Python :

    A melhor descrição está aqui: O que são metaclasses no Python?

Tadeck
fonte
3
Essas duas coisas estão relacionadas? ou seja, a Metaclasse interna do Django impede que você use os recursos de metaclasse incorporados do Python?
N15 de
10
@ Nnyby: Há duas coisas que criam relação entre esses dois conceitos: nome e confusão que muitos usuários têm (como o OP tinha na pergunta original). Acredito que abordar essa confusão comum é uma vantagem significativa desse tópico. Você não concorda?
Tadeck 03/03
48

Estendendo a resposta Django de Tadeck acima, o uso de 'class Meta:' no Django também é apenas Python normal.

A classe interna é um espaço de nomes conveniente para dados compartilhados entre as instâncias da classe (daí o nome Meta para 'metadados', mas você pode chamá-lo como quiser). Enquanto no Django geralmente é um material de configuração somente leitura, não há nada para impedir que você mude:

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

Você também pode explorá-lo diretamente no Django, por exemplo:

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>}

No entanto, no Django é mais provável que você queira explorar o _metaatributo que é um Optionsobjeto criado pelo modelo metaclassquando ele é criado. É aqui que você encontrará todas as informações 'meta' da classe Django. No Django, Metaé usado apenas para passar informações ao processo de criação do _meta Optionsobjeto.

Paul Whipp
fonte
Isso não funciona nos modelos definidos pelo usuário: >>> do myapp.models importa o MyModel >>> MyModel.Meta Traceback (última chamada mais recente): arquivo "<console>", linha 1, em <module> AttributeError: objeto de tipo 'MyModel' não tem atributo 'meta'
bdf 11/12/2015
2
Você precisa do sublinhado, por exemplo,MyUser.objects.get(pk=1)._meta
Paul Whipp 13/12
Certo, mas isso não acessa a classe Meta interna da classe Model. Isso acessa as opções _meta para a instância desse modelo ... não parece haver uma maneira de acessar a própria classe Meta interna. O caso de uso para mim foi subclassificar uma classe proxy MyModelProxy de MyModel de uma maneira em que MyModelProxy possa herdar a classe Meta interna do MyModel.
Bd
Não estou totalmente esclarecido sobre o que você quer dizer com 'classe Meta interna' do modelo, mas você sempre pode trabalhar diretamente com a classe da instância, por exemplotype(MyUser.objects.get(pk=1)).Meta
Paul Whipp
2
"namespace conveniente para dados compartilhados entre as instâncias da classe" Essa linha fez isso por mim.
MGP 14/11
22

A Modelclasse do Django lida especificamente com um atributo chamado Metaqual é uma classe. Não é uma coisa geral do Python.

As metaclasses do Python são completamente diferentes.

Âmbar
fonte
12
Acho que sua resposta não é clara o suficiente - você poderia elaborar como a Metaclasse funciona? Eu acredito que o OP perguntou especificamente sobre isso.
Tadeck
6

Respostas que reivindicam o modelo do Django Meta e metaclasses do são "completamente diferentes" são respostas enganosas.

A construção dos objetos de classe do modelo Django (ou seja, o objeto que representa a própria definição de classe; sim, classes também são objetos) são realmente controlados por uma metaclasse chamada ModelBase, você pode ver esse código aqui:

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

E uma das coisas que ModelBasefaz é criar o _metaatributo em todos os modelos do Django que contenham mecanismos de validação, detalhes de campo, salvar lógica e assim por diante. Durante esta operação, o material especificado nas partes internas do modeloMeta classe são lidas e usadas nesse processo.

Então, enquanto sim, em certo sentido, Metae as metaclasses são 'coisas' diferentes, dentro da mecânica da construção do modelo do Django elas estão intimamente relacionadas; a compreensão de como eles funcionam juntos aprofundará sua percepção dos dois ao mesmo tempo.

Esta pode ser uma fonte útil de informações para entender melhor como os modelos do Django empregam metaclasses.

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

E isso também pode ajudar se você quiser entender melhor como os objetos funcionam em geral.

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

jhrr
fonte
0

Documento da classe Meta interna Este documento dos metadados do django Model é "qualquer coisa que não seja um campo", como opções de pedido (pedido), nome da tabela do banco de dados (db_table) ou nomes singulares e plurais legíveis por humanos (verbose_name e verbose_name_plural). Nenhuma é necessária e a adição de classe Meta a um modelo é completamente opcional. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
fonte
0

No Django, ele atua como uma classe de configuração e mantém os dados de configuração em um só lugar !!

Rishi Chhabra
fonte