¿Cómo funciona la clase Meta de Django?

191

Estoy usando Django que permite a las personas agregar parámetros adicionales a una clase mediante el uso class Meta.

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

Lo único que encontré en la documentación de Python fue:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Sin embargo, no creo que sea lo mismo.

miki725
fuente
66
El título pregunta sobre el meta de Python, pero parece preguntarse sobre el meta de Django: ¿sobre cuál pregunta?
ckhan
10
@ckhan está confundido debido a la decisión absurda (IMO) de llamar a una clase anidada "Meta", que es muy engañosa; para principiantes, sobre las metaclases de Python, y para usuarios más experimentados que nunca lo han visto, sobre su propósito a priori (en lugar de usar atributos de clase o metaclases reales)
JC Rocamonde

Respuestas:

234

Estás haciendo una pregunta sobre dos cosas diferentes:

  1. Metaclase interna en modelos Django :

    Esto es solo un contenedor de clase con algunas opciones (metadatos) adjuntas al modelo. Define cosas como los permisos disponibles, el nombre de la tabla de la base de datos asociada, si el modelo es abstracto o no, las versiones en singular y plural del nombre, etc.

    Breve explicación está aquí: Django docs: Modelos: Meta opciones

    La lista de meta opciones disponibles está aquí: Django docs: Model Meta options

    Para la última versión de Django: Django docs: Model Meta options

  2. Metaclase en Python :

    La mejor descripción está aquí: ¿Qué son las metaclases en Python?

Tadeck
fuente
3
¿Estas dos cosas están relacionadas en absoluto? es decir, ¿la Metaclase interna de Django le impide usar las funciones integradas de metaclase de Python?
nnyby
10
@nnyby: Hay dos cosas que crean una relación entre estos dos conceptos: nombre y confusión que tienen muchos usuarios (como OP tenía en la pregunta original). Creo que abordar esa confusión común es una ventaja significativa de este tema. No estas de acuerdo
Tadeck
49

Extendiendo la respuesta anterior de Tadeck a Django, el uso de 'clase Meta:' en Django también es Python normal.

La clase interna es un espacio de nombres conveniente para los datos compartidos entre las instancias de la clase (de ahí el nombre Meta para 'metadatos' pero puede llamarlo como quiera). Si bien en Django generalmente se trata de configuraciones de solo lectura, no hay nada que lo detenga para cambiarlo:

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

También puede explorarlo en Django directamente, por ejemplo:

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

Sin embargo, en Django es más probable que desee explorar el _metaatributo que es un Optionsobjeto creado por el modelo metaclasscuando se crea un modelo. Ahí es donde encontrará toda la información 'meta' de la clase Django. En Django, Metasolo se usa para pasar información al proceso de creación del _meta Optionsobjeto.

Paul Whipp
fuente
Esto no funciona en modelos definidos por el usuario: >>> desde myapp.models import MyModel >>> MyModel.Meta Traceback (última llamada reciente): Archivo "<consola>", línea 1, en <módulo> AttributeError: tipo de objeto 'MyModel' no tiene atributo 'meta'
bdf
2
Necesitas el guión bajo, por ejemploMyUser.objects.get(pk=1)._meta
Paul Whipp
Correcto, pero eso no accede a la clase interna Meta de la clase Modelo. Eso accede a las opciones _meta para la instancia de ese Modelo ... no parece haber una forma de acceder a la clase Meta interna. El caso de uso para mí fue la subclase de una clase MyModelProxy proxy de MyModel de manera que MyModelProxy pueda heredar la clase Meta interna de MyModel.
bdf
No tengo del todo claro qué quiere decir con la 'clase meta interna' del modelo, pero siempre puede trabajar directamente con la clase de la instancia, por ejemplotype(MyUser.objects.get(pk=1)).Meta
Paul Whipp,
3
"espacio de nombres conveniente para datos compartidos entre las instancias de clase" Esa línea lo hizo por mí.
Pop
22

La Modelclase de Django maneja específicamente tener un atributo llamado Metaque es una clase. No es una cosa general de Python.

Las metaclases de Python son completamente diferentes.

Ámbar
fuente
12
Creo que su respuesta no es lo suficientemente clara: ¿podría explicar cómo Metafunciona la clase? Creo que OP preguntó específicamente sobre eso.
Tadeck
7

Las respuestas que afirman que el modelo Metay las metaclases de Django son "completamente diferentes" son respuestas engañosas.

La construcción de los objetos de clase modelo de Django (es decir, el objeto que representa la definición de clase en sí; sí, las clases también son objetos) de hecho están controlados por una metaclase llamada ModelBase, puede ver ese código aquí:

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

Y una de las cosas que ModelBasehace es crear el _metaatributo en cada modelo de Django que contiene maquinaria de validación, detalles de campo, lógica de guardado, etc. Durante esta operación, las cosas que se especifican en la Metaclase interna del modelo se leen y usan dentro de ese proceso.

Entonces, aunque sí, en cierto sentido Metay las metaclases son 'cosas' diferentes, dentro de la mecánica de la construcción del modelo Django están íntimamente relacionadas; Comprender cómo funcionan juntos profundizará su comprensión de ambos a la vez.

Esta podría ser una fuente útil de información para comprender mejor cómo los modelos Django emplean metaclases.

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

Y esto también podría ayudar si desea comprender mejor cómo funcionan los objetos en general.

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

jhrr
fuente
0

Documento interno de metaclases Este documento de metadatos del modelo django es "cualquier cosa que no sea un campo", como las opciones de pedido (pedido), el nombre de la tabla de la base de datos (db_table) o los nombres en singular y plural legibles por humanos (verbose_name y verbose_name_plural). No se requiere ninguno, y agregar la clase Meta a un modelo es completamente opcional. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
fuente
0

¡En Django, actúa como una clase de configuración y mantiene los datos de configuración en un solo lugar!

Rishi Chhabra
fuente