Comment fonctionne la classe Meta de Django?

206

J'utilise Django qui permet aux gens d'ajouter des paramètres supplémentaires à une classe en utilisant class Meta.

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

La seule chose que j'ai trouvée dans la documentation de Python était:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Cependant, je ne pense pas que ce soit la même chose.

miki725
la source
6
Le titre pose des questions sur la méta de Python, mais la question semble se poser sur la méta de Django - laquelle parlez-vous?
ckhan
12
@ckhan il est confus en raison de la décision absurde (IMO) d'appeler une classe imbriquée "Meta", ce qui est très trompeur; aux débutants, à propos des métaclasses de Python, et aux utilisateurs plus expérimentés qui ne l'ont jamais vue, à propos de son objectif a priori (au lieu d'utiliser des attributs de classe ou de vraies métaclasses)
JC Rocamonde

Réponses:

245

Vous posez une question sur deux choses différentes:

  1. Metaclasse interne dans les modèles Django :

    Ceci est juste un conteneur de classe avec quelques options (métadonnées) attachées au modèle. Il définit des éléments tels que les autorisations disponibles, le nom de la table de base de données associée, si le modèle est abstrait ou non, les versions singulière et plurielle du nom, etc.

    Une brève explication est ici: Django docs: Models: Meta options

    La liste des méta-options disponibles est ici: Django docs: Model Meta options

    Pour la dernière version de Django: docs Django: Options du modèle Meta

  2. Métaclasse en Python :

    La meilleure description est ici: Que sont les métaclasses en Python?

Tadeck
la source
3
Ces deux choses sont-elles liées du tout? c'est-à-dire, la Metaclasse interne de Django vous empêche-t-elle d'utiliser les fonctionnalités de métaclasse intégrées de Python?
nnyby
10
@nnyby: Il y a deux choses qui créent une relation entre ces deux concepts: le nom et la confusion que de nombreux utilisateurs ont (comme OP l'avait fait dans la question originale). Je crois que résoudre cette confusion commune est un avantage significatif de ce topi. Tu n'es pas d'accord?
Tadeck
51

S'étendant sur la réponse Django de Tadeck ci-dessus, l'utilisation de 'class Meta:' dans Django est également un Python normal.

La classe interne est un espace de noms pratique pour les données partagées entre les instances de classe (d'où le nom Meta pour «métadonnées» mais vous pouvez l'appeler comme vous le souhaitez). Alors que dans Django, il s'agit généralement de configuration en lecture seule, rien ne vous empêche de le changer:

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

Vous pouvez également l'explorer directement dans Django, par exemple:

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

Cependant, dans Django, vous êtes plus susceptible de vouloir explorer l' _metaattribut qui est un Optionsobjet créé par le modèle metaclasslors de la création d'un modèle. C'est là que vous trouverez toutes les informations «méta» de la classe Django. Dans Django, Metaest simplement utilisé pour transmettre des informations dans le processus de création de l' _meta Optionsobjet.

Paul Whipp
la source
Cela ne fonctionne pas sur les modèles définis par l'utilisateur: >>> à partir de myapp.models importer MyModel >>> MyModel.Meta Traceback (dernier appel en dernier): Fichier "<console>", ligne 1, dans <module> AttributeError: L'objet de type 'MyModel' n'a pas d'attribut 'meta'
bdf
2
Vous avez besoin du trait de soulignement, par exempleMyUser.objects.get(pk=1)._meta
Paul Whipp
Bien, mais cela n'accède pas à la classe Meta interne de la classe Model. Cela accède aux options _meta pour l'instance de ce modèle ... il ne semble pas y avoir de moyen d'accéder à la classe Meta interne elle-même. Le cas d'utilisation pour moi était de sous-classer une classe MyModelProxy proxy de MyModel d'une manière où MyModelProxy peut hériter de la classe Meta interne de MyModel.
bdf
Je ne suis pas tout à fait clair sur ce que vous entendez par «classe Meta interne» du modèle, mais vous pouvez toujours travailler directement avec la classe de l'instance, par exempletype(MyUser.objects.get(pk=1)).Meta
Paul Whipp
3
"espace de noms pratique pour les données partagées entre les instances de classe" Cette ligne l'a fait pour moi.
MGP
22

La Modelclasse de Django gère spécifiquement le fait d'avoir un attribut nommé Metaqui est une classe. Ce n'est pas un truc Python général.

Les métaclasses Python sont complètement différentes.

ambre
la source
12
Je pense que votre réponse n'est pas assez claire - pourriez-vous expliquer comment Metafonctionne la classe? Je crois qu'OP a posé une question spécifique à ce sujet.
Tadeck
8

Les réponses qui prétendent que le modèle Django Metaet les métaclasses sont «complètement différents» sont des réponses trompeuses.

La construction des objets de classe de modèle Django , c'est-à-dire l'objet qui représente la définition de classe elle-même (oui, les classes sont aussi des objets), est en effet contrôlée par une métaclasse appelée ModelBase, et vous pouvez voir ce code ici .

Et l'une des choses à ModelBasefaire est de créer l' _metaattribut sur chaque modèle Django qui contient des machines de validation, des détails de champ, une logique de sauvegarde, etc. Au cours de cette opération, les éléments spécifiés dans la Metaclasse interne du modèle sont lus et utilisés dans ce processus.

Donc, alors que oui, dans un sens Metaet les métaclasses sont des «choses» différentes, dans la mécanique de la construction du modèle Django, elles sont intimement liées; comprendre comment ils fonctionnent ensemble approfondira votre vision des deux à la fois.

Cela peut être une source d'informations utile pour mieux comprendre comment les modèles Django utilisent des métaclasses.

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

Et cela peut également vous aider si vous souhaitez mieux comprendre le fonctionnement des objets en général.

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

jhrr
la source
1

Dans Django, il agit comme une classe de configuration et conserve les données de configuration au même endroit !!

Rishi Chhabra
la source
0

Document de méta-classe interne Ce document de métadonnées du modèle django est «tout ce qui n'est pas un champ», comme les options de tri (ordre), le nom de la table de la base de données (db_table), ou les noms singuliers et pluriels lisibles par l'homme (verbose_name et verbose_name_plural). Aucun n'est requis et l'ajout de la classe Meta à un modèle est complètement facultatif. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
la source
0

Class Meta est l'endroit dans votre logique de code où vos model.fields RENCONTRENT avec vos form.widgets . Ainsi, sous Classe Meta (), vous créez le lien entre les champs de votre modèle et les différents widgets que vous souhaitez avoir dans votre formulaire.

HassanSh__3571619
la source