Wie funktioniert Djangos Meta-Klasse?

189

Ich verwende Django, mit dem Leute einer Klasse zusätzliche Parameter hinzufügen können, indem sie verwenden class Meta .

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

Das einzige, was ich in Pythons Dokumentation gefunden habe, war:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Ich denke jedoch nicht, dass dies dasselbe ist.

miki725
quelle
6
Der Titel fragt nach Python-Meta, aber die Frage scheint nach Django-Meta zu fragen - nach welchem ​​fragen Sie?
Ckhan
10
@ckhan er ist verwirrt wegen der absurden Entscheidung (IMO), eine verschachtelte Klasse "Meta" zu nennen, was sehr irreführend ist; Anfängern, über Pythons Metaklassen und erfahrenen Benutzern, die sie noch nie gesehen haben, über ihren Zweck a priori (anstatt Klassenattribute oder echte Metaklassen zu verwenden)
JC Rocamonde

Antworten:

231

Sie stellen eine Frage zu zwei verschiedenen Dingen:

  1. Metainnere Klasse in Django-Modellen :

    Dies ist nur ein Klassencontainer mit einigen Optionen (Metadaten), die an das Modell angehängt sind. Es definiert Dinge wie verfügbare Berechtigungen, den Namen der zugehörigen Datenbanktabelle, ob das Modell abstrakt ist oder nicht, Singular- und Pluralversionen des Namens usw.

    Eine kurze Erklärung finden Sie hier: Django-Dokumente: Modelle: Meta-Optionen

    Eine Liste der verfügbaren Metaoptionen finden Sie hier: Django-Dokumente: Modell-Metaoptionen

    Für die neueste Version von Django: Django docs: Model Meta options

  2. Metaklasse in Python :

    Die beste Beschreibung finden Sie hier: Was sind Metaklassen in Python?

Tadeck
quelle
3
Sind diese beiden Dinge überhaupt miteinander verbunden? MetaVerhindert die innere Klasse von Django, dass Sie die integrierten Metaklassenfunktionen von Python verwenden können?
Nnyby
10
@nnyby: Es gibt zwei Dinge, die eine Beziehung zwischen diesen beiden Konzepten herstellen: Name und Verwirrung, die viele Benutzer haben (wie OP es in der ursprünglichen Frage hatte). Ich glaube, dass die Beseitigung dieser allgemeinen Verwirrung ein wesentlicher Vorteil dieser Topi ist. Stimmst du nicht zu?
Tadeck
48

In Anlehnung an Tadecks Django-Antwort oben ist die Verwendung von 'class Meta:' in Django auch nur normales Python.

Die interne Klasse ist ein praktischer Namespace für gemeinsam genutzte Daten zwischen den Klasseninstanzen (daher der Name Meta für 'Metadaten', aber Sie können ihn beliebig nennen). Während es in Django im Allgemeinen schreibgeschützt ist, gibt es nichts, was Sie daran hindert, es zu ändern:

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

Sie können es auch direkt in Django erkunden, zB:

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

In Django möchten Sie jedoch eher das _metaAttribut untersuchen, bei dem es sich um ein OptionsObjekt handelt, das vom Modell erstellt wird, metaclasswenn ein Modell erstellt wird. Hier finden Sie alle Meta-Informationen der Django-Klasse. In Django Metawird nur verwendet, um Informationen in den Prozess der Erstellung des _meta OptionsObjekts zu übergeben.

Paul Whipp
quelle
Dies funktioniert nicht bei benutzerdefinierten Modellen: >>> aus myapp.models importieren MyModel >>> MyModel.Meta Traceback (letzter Aufruf zuletzt): Datei "<console>", Zeile 1, in <module> AttributeError: Typ Objekt 'MyModel' hat kein Attribut 'Meta'
bdf
2
Sie benötigen den Unterstrich zBMyUser.objects.get(pk=1)._meta
Paul Whipp
Richtig, aber das greift nicht auf die innere Meta-Klasse der Modellklasse zu. Damit wird auf die _meta-Optionen für die Instanz dieses Modells zugegriffen. Es scheint keine Möglichkeit zu geben, auf die innere Meta-Klasse selbst zuzugreifen. Der Anwendungsfall für mich bestand darin, eine Proxy-MyModelProxy-Klasse von MyModel so zu unterordnen, dass MyModelProxy die innere Meta-Klasse von MyModel erben kann.
bdf
Mir ist nicht ganz klar, was Sie unter der "inneren Meta-Klasse" des Modells verstehen, aber Sie können immer direkt mit der Klasse der Instanz arbeiten, z. B.type(MyUser.objects.get(pk=1)).Meta
Paul Whipp,
2
"Praktischer Namespace für gemeinsam genutzte Daten zwischen den Klasseninstanzen" Diese Zeile hat es für mich getan.
MGP
22

Die ModelKlasse von Django behandelt speziell das AttributMeta das eine Klasse ist. Es ist keine allgemeine Python-Sache.

Python-Metaklassen sind völlig anders.

Bernstein
quelle
12
Ich denke, Ihre Antwort ist nicht klar genug - können Sie näher erläutern, wie der MetaUnterricht funktioniert? Ich glaube, OP hat speziell danach gefragt.
Tadeck
6

Antworten, die Django-Modelle beanspruchen Meta und Metaklassen seien "völlig unterschiedlich", sind irreführende Antworten.

Die Konstruktion von Django Modell Klassenobjekten (das das Objekt zu sagen ist , die für die Klassendefinition steht selbst, ja, Klassen werden auch Objekte) sind in der Tat von einem metaclass gesteuert genannt ModelBase, können Sie diesen Code hier sehen:

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

Und eines der Dinge, ModelBasedie Sie _metatun müssen, ist, das Attribut für jedes Django-Modell zu erstellen, das Validierungsmaschinerie, Felddetails, Speicherlogik usw. enthält. Während dieses Vorgangs das Material, das im Inneren des Modells angegeben istMeta Klasse gelesen und in diesem Prozess verwendet.

Während ja, in Metagewissem Sinne und Metaklassen unterschiedliche „Dinge“ sind, sind sie innerhalb der Mechanik des Django-Modellbaus eng miteinander verbunden. Wenn Sie verstehen, wie sie zusammenarbeiten, vertiefen Sie Ihren Einblick in beide gleichzeitig.

Dies könnte eine hilfreiche Informationsquelle sein, um besser zu verstehen, wie Django-Modelle Metaklassen verwenden.

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

Dies kann auch hilfreich sein, wenn Sie besser verstehen möchten, wie Objekte im Allgemeinen funktionieren.

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

jhrr
quelle
0

Dokument der inneren Metaklasse Dieses Dokument der Metadaten des Django-Modells ist „alles, was kein Feld ist“, z. B. Bestelloptionen (Reihenfolge), Name der Datenbanktabelle (db_table) oder lesbare Singular- und Pluralnamen (Verbose_name und Verbose_name_plural). Es sind keine erforderlich, und das Hinzufügen der Klasse Meta zu einem Modell ist völlig optional. https://docs.djangoproject.com/de/dev/topics/db/models/#meta-options

Sujeet
quelle
0

In Django fungiert es als Konfigurationsklasse und speichert die Konfigurationsdaten an einem Ort !!

Rishi Chhabra
quelle