2012-04-27 6 views
115

Utilizzo Django che consente alle persone di aggiungere parametri aggiuntivi a una classe utilizzando class Meta.Come funziona la classe Meta di Django?

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

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

class FooMetaClass(type): 
    ... 

class FooClass: 
    __metaclass__ = FooMetaClass 

Tuttavia, non credo che questa è la stessa cosa.

+3

Titolo chiede di Python meta, ma questione sembra chiedere di Django meta - quale stai chiedendo circa? – ckhan

risposta

145

Stai chiedendo una domanda di due cose diverse:

  1. Meta classe interna nei modelli Django:

    Questo è solo un contenitore di classe con alcune opzioni (metadati) collegati al modello di . Definisce cose come autorizzazioni disponibili, associata nome della tabella del database, se il modello è astratto o no, singolare e plurale versioni del nome ecc

    Breve spiegazione è qui: Django docs: Models: Meta options

    Elenco delle opzioni disponibili è meta qui: Django docs: Model Meta options

  2. metaclasse in Python:

    La migliore descrizione è qui: What is a metaclass in Python?

+1

Queste due cose sono collegate? cioè, la classe interna di 'Meta' di Django ti impedisce di utilizzare le funzionalità di metaclass incorporate di Python? – nnyby

+7

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

19

La classe di Django Model gestisce in modo specifico un attributo denominato Meta che è una classe. Non è una cosa generale di Python.

Metaclasses Python sono completamente diversi.

+11

Penso che la tua risposta non sia abbastanza chiara - potresti approfondire come funziona la classe Meta? Credo che OP abbia chiesto specificamente a riguardo. – Tadeck

34

Estendendo la risposta di Djad di Tadeck in alto, l'uso di "classe Meta:" in Django è anche normale Python.

La classe interna è un comodo spazio dei nomi per i dati condivisi tra le istanze di classe (da qui il nome Meta per "metadati" ma è possibile chiamarlo come preferisci). Mentre in Django è generalmente letta solo roba di configurazione, 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 

è possibile esplorare in Django direttamente 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 si è più probabile che voglia esplorare l'attributo _meta che è un oggetto Options creato dal metaclasse del modello quando viene creato un modello. È qui che troverai tutte le informazioni "meta" della classe Django. In Django, Meta è semplicemente usato per passare informazioni nel processo di creazione dell'oggetto _meta Options.

+0

Questo non funziona su modelli definiti dall'utente: >>> da myapp.models importare MyModel >>> MyModel.Meta Traceback (chiamata più recente scorso): file "", la linea 1, in AttributeError: tipo oggetto 'MyModel' non ha attributo 'meta' – bdf

+0

È necessario il carattere di sottolineatura es. 'MyUser.objects.get (pk = 1) ._ meta' –

+0

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

1

Le risposte che affermano che il modello Meta di Django e "metaclassi" sono "completamente differenti" sono risposte fuorvianti.

La costruzione del modello di Django classe oggetti (vale a dire l'oggetto che sta per la definizione della classe stessa) sono infatti controllati da un metaclasse chiamato ModelBase, si può vedere che il codice qui:

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

E una delle cose che lo ModelBase fa è creare l'attributo su ogni modello Django che contiene macchinari di convalida, dettagli sul campo, macchine di risparmio e così via. E, durante questa operazione, tutto ciò che è specificato nella classe interna Meta del modello viene letto e utilizzato all'interno di quel processo.

Quindi, mentre sì, in un certo senso Meta e metaclassi sono "cose" differenti, all'interno della meccanica del modello di costruzione di Django sono intimamente correlati; capire come lavorano insieme approfondirà la tua visione di entrambi contemporaneamente.

Questa potrebbe essere una utile fonte di informazioni per capire meglio come i modelli Django utilizzano i metaclassi.

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

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

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