Come funziona la classe Meta di Django?


191

Sto usando Django che consente alle persone di aggiungere parametri extra a una classe usando class Meta.

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

L'unica cosa che ho trovato nella documentazione di Python era:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Tuttavia, non penso che sia la stessa cosa.


6
Il titolo chiede della meta Python, ma la domanda sembra porre sulla meta Django - di quale stai chiedendo?
ckhan,

10
@ckhan è confuso a causa dell'assurda decisione (IMO) di chiamare una classe nidificata "Meta", che è molto fuorviante; ai principianti, alle metaclasse di Python e agli utenti più esperti che non l'hanno mai visto, sul suo scopo a priori (invece di usare attributi di classe o metaclasse reali)
JC Rocamonde,

Risposte:


234

Stai ponendo una domanda su due cose diverse:

  1. Metaclasse interna nei modelli Django :

    Questo è solo un contenitore di classe con alcune opzioni (metadati) associate al modello. Definisce elementi quali autorizzazioni disponibili, nome della tabella del database associato, indipendentemente dal fatto che il modello sia astratto o meno, versioni singolari e plurali del nome, ecc.

    Ecco una breve spiegazione: documenti Django: modelli: opzioni Meta

    L'elenco delle meta opzioni disponibili è qui: Documenti Django: opzioni Meta modello

    Per l'ultima versione di Django: documenti Django: opzioni Meta modello

  2. Metaclasse in Python :

    La migliore descrizione è qui: cosa sono i metaclassi in Python?


3
Queste due cose sono assolutamente correlate? cioè, la Metaclasse interiore di Django ti impedisce di usare le funzionalità di metaclasse integrate di Python?
nnyby,

10
@nnyby: ci sono due cose che creano una relazione tra questi due concetti: nome e confusione che hanno molti utenti (come OP aveva nella domanda originale). Credo che affrontare questa confusione comune sia un vantaggio significativo di questo argomento. Non sei d'accordo?
Tadeck,

49

Estendendo la risposta Django di Tadeck sopra, l'uso della 'classe Meta:' in Django è anche un normale Python.

La classe interna è un comodo spazio dei nomi per i dati condivisi tra le istanze della classe (da qui il nome Meta per "metadati" ma puoi chiamarlo come preferisci). Mentre in Django è generalmente roba di configurazione di sola lettura, non c'è nulla che impedisca di cambiarla:

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

Puoi esplorarlo direttamente in Django anche ad esempio:

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

Tuttavia, in Django è più probabile che tu voglia esplorare l' _metaattributo che è un Optionsoggetto creato dal modello metaclassquando viene creato un modello. Qui troverai tutte le informazioni "meta" della classe Django. In Django, Metaviene utilizzato solo per passare informazioni nel processo di creazione _meta Optionsdell'oggetto.


Questo non funziona sui modelli definiti dall'utente: >>> da myapp.models import MyModel >>> MyModel.Meta Traceback (ultima chiamata più recente): File "<console>", riga 1, in <module> AttributeError: l'oggetto tipo "MyModel" non ha attributo "meta"
bdf

2
È necessario il carattere di sottolineatura, ad esempioMyUser.objects.get(pk=1)._meta
Paul Whipp il

Giusto, ma ciò non accede alla classe Meta interna della classe del Modello. Questo accede alle opzioni _meta per l'istanza di quel Modello ... non sembra esserci un modo per accedere alla classe Meta interna stessa. Il caso d'uso per me era la sottoclasse di una classe proxy MyModelProxy da MyModel in un modo in cui MyModelProxy può ereditare la classe Meta interna di MyModel.
bdf

Non sono del tutto chiaro su cosa intendi per "classe Meta interna" del modello, ma puoi sempre lavorare direttamente con la classe dell'istanza, ad esempiotype(MyUser.objects.get(pk=1)).Meta
Paul Whipp,

3
"comodo spazio dei nomi per i dati condivisi tra le istanze di classe" Quella linea l'ha fatto per me.
MGP

22

La Modelclasse di Django gestisce in modo specifico avere un attributo chiamato Metache è una classe. Non è una cosa generale di Python.

I metaclassi Python sono completamente diversi.


12
Penso che la tua risposta non sia abbastanza chiara: potresti approfondire come Metafunziona la lezione? Credo che l'OP abbia chiesto specificamente questo.
Tadeck,

7

Risposte che rivendicano il modello di Django Meta e le metaclasse di sono "completamente diversi" sono risposte fuorvianti.

La costruzione di oggetti di classe del modello Django (vale a dire l'oggetto che rappresenta la definizione della classe stessa; sì, le classi sono anche oggetti) sono effettivamente controllati da una metaclasse chiamata ModelBase, puoi vedere quel codice qui:

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

E una delle cose che ModelBasefa è creare l' _metaattributo su ogni modello Django che contiene macchinari di validazione, dettagli sul campo, logica di salvataggio e così via. Durante questa operazione, le cose specificate nella Metaclasse interna del modello vengono lette e utilizzate all'interno di quel processo.

Quindi, mentre sì, in un certo senso Meta e le metaclasse siano "cose" diverse, all'interno della meccanica della costruzione del modello Django sono intimamente correlate; capire come lavorano insieme approfondirà la tua comprensione di entrambi contemporaneamente.

Questa potrebbe essere un'utile fonte di informazioni per comprendere meglio come i modelli Django impiegano metaclassi.

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

E questo potrebbe aiutare anche se vuoi capire meglio come funzionano gli oggetti in generale.

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


0

Documento Meta Class interna Questo documento dei metadati del modello django è "tutto ciò che non è un campo", come opzioni di ordinamento (ordinamento), nome della tabella del database (db_table) o nomi singolari e plurali leggibili dall'uomo (verbose_name e verbose_name_plural). Nessuno è richiesto e l'aggiunta della classe Meta a un modello è completamente facoltativa. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options


0

In Django, funge da classe di configurazione e mantiene i dati di configurazione in un unico posto !!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.