Jak działa klasa Metjan Django?

191

Używam Django, który pozwala ludziom dodawać dodatkowe parametry do klasy za pomocą class Meta.

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

Jedyne, co znalazłem w dokumentacji Pythona, to:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Jednak nie sądzę, że to jest to samo.

miki725
źródło
6
Tytuł pyta o meta Pythona, ale wydaje się, że pyta o meta Django - o którą pytasz?
ckhan
10
@ckhan jest zdezorientowany z powodu absurdalnej decyzji (IMO), aby nazwać klasę zagnieżdżoną „Meta”, co jest bardzo mylące; początkującym, o metaklasach Pythona i bardziej doświadczonym użytkownikom, którzy nigdy go nie widzieli, o jego przeznaczeniu a priori (zamiast używania atrybutów klas lub prawdziwych metaklas)
JC Rocamonde

Odpowiedzi:

233

Zadajesz pytanie o dwie różne rzeczy:

  1. Metaklasa wewnętrzna w modelach Django :

    To tylko kontener klasy z kilkoma opcjami (metadanymi) dołączonymi do modelu. Definiuje takie rzeczy, jak dostępne uprawnienia, powiązana nazwa tabeli bazy danych, czy model jest abstrakcyjny czy nie, pojedyncze i mnogie wersje nazwy itp.

    Krótkie wyjaśnienie jest tutaj: Dokumenty Django: Modele: Opcje Meta

    Lista dostępnych opcji meta jest tutaj: Dokumenty Django: Opcje Meta modelu

    Najnowsza wersja Django: Django docs: Model Meta options

  2. Metaklasa w Pythonie :

    Najlepszy opis znajduje się tutaj: Co to są metaklasy w Pythonie?

Tadeck
źródło
3
Czy te dwie rzeczy są w ogóle powiązane? tzn. czy Metawewnętrzna klasa Django uniemożliwia korzystanie z wbudowanych funkcji metaklasy Pythona?
nnyby
10
@nnyby: Istnieją dwie rzeczy, które tworzą relację między tymi dwoma pojęciami: nazwa i zamieszanie, które wielu użytkowników ma (tak jak OP miało to w pierwotnym pytaniu). Uważam, że rozwiązanie tego powszechnego zamieszania jest znaczącą zaletą tego topi. Nie zgadzasz się
Tadeck
49

Rozszerzając powyższą odpowiedź Django Tadecka, użycie „class Meta:” w Django jest również zwykłym Pythonem.

Klasa wewnętrzna jest wygodną przestrzenią nazw dla współużytkowanych danych między instancjami klasy (stąd nazwa Meta dla „metadanych”, ale można ją nazwać jak tylko zechcesz). Podczas gdy w Django jest to konfiguracja tylko do odczytu, nic nie stoi na przeszkodzie, abyś ją zmienił:

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

Możesz to również zbadać bezpośrednio w Django, np .:

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

Jednak w Django chętniej eksplorujesz _metaatrybut, którym jest Optionsobiekt tworzony przez model metaclasspodczas tworzenia modelu. W tym miejscu znajdziesz wszystkie informacje „meta” klasy Django. W Django Metasłuży tylko do przekazywania informacji do procesu tworzenia _meta Optionsobiektu.

Paul Whipp
źródło
To nie działa na modelach zdefiniowanych przez użytkownika: >>> z myapp.models import MyModel >>> MyModel.Meta Traceback (ostatnie połączenie ostatnio): Plik „<console>”, wiersz 1, w <module> AttributeError: typ obiektu „MyModel” nie ma atrybutu „meta”
bdf
2
Potrzebujesz podkreślenia, np.MyUser.objects.get(pk=1)._meta
Paul Whipp
Zgadza się, ale nie ma dostępu do wewnętrznej klasy Meta klasy Modelki. Uzyskuje to dostęp do opcji _meta dla instancji Modelu ... wydaje się, że nie ma sposobu na uzyskanie dostępu do wewnętrznej klasy Meta. Przypadkiem użycia dla mnie było podklasowanie klasy proxy MyModelProxy z MyModel w taki sposób, że MyModelProxy może odziedziczyć wewnętrzną klasę Meta MyModel.
bdf
Nie do końca rozumiem, co rozumiesz przez „wewnętrzną klasę Meta” modelu, ale zawsze możesz bezpośrednio pracować z klasą instancji, np.type(MyUser.objects.get(pk=1)).Meta
Paul Whipp
3
„dogodna przestrzeń nazw dla współdzielonych danych między instancjami klasy” Ta linia zrobiła to dla mnie.
MGP
22

ModelKlasa Django obsługuje konkretnie atrybuty o nazwie Metaklasa. To nie jest ogólna kwestia Python.

Metaklasy Pythona są zupełnie inne.

Bursztyn
źródło
12
Myślę, że twoja odpowiedź nie jest wystarczająco jasna - czy mógłbyś rozwinąć sposób działania Metaklasy? Uważam, że OP zapytał konkretnie o to.
Tadeck
7

Odpowiedzi, które twierdzą, że model Django Meta i metaklasy są „zupełnie inne”, są mylącymi odpowiedziami.

Konstrukcja obiektów klasy modelu Django (to znaczy obiektu, który oznacza samą definicję klasy; tak, klasy są również obiektami) jest rzeczywiście kontrolowana przez metaklasę o nazwie ModelBase, możesz zobaczyć ten kod tutaj:

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

Jedną z rzeczy, które ModelBaseto robi, jest utworzenie _metaatrybutu na każdym modelu Django, który zawiera maszynę do sprawdzania poprawności, szczegóły pola, logikę składowania i tak dalej. Podczas tej operacji elementy określone w wewnętrznej Metaklasie modelu są odczytywane i wykorzystywane w tym procesie.

A więc w pewnym sensie tak Meta metaklasy są różnymi „rzeczami”, w mechanice konstrukcji modelu Django są one ściśle powiązane; zrozumienie, jak one działają razem, pogłębi twój wgląd w oba naraz.

Może to być pomocne źródło informacji, aby lepiej zrozumieć, w jaki sposób modele Django wykorzystują metaklasy.

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

Może to również pomóc, jeśli chcesz lepiej zrozumieć, jak ogólnie działają obiekty.

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

jhrr
źródło
0

Dokument wewnętrznej klasy meta Ten dokument metadanych Modelu django to „wszystko, co nie jest polem”, takie jak opcje zamawiania (zamawianie), nazwa tabeli bazy danych (tablica_db) lub czytelne dla człowieka nazwy w liczbie pojedynczej i mnogiej (nazwa_grubna i nazwa_grubna). Żadne nie są wymagane, a dodanie klasy Meta do modelu jest całkowicie opcjonalne. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
źródło
0

W Django działa jak klasa konfiguracyjna i utrzymuje dane konfiguracyjne w jednym miejscu !!

Rishi Chhabra
źródło