Bagaimana cara kerja kelas Meta Django?

191

Saya menggunakan Django yang memungkinkan orang untuk menambahkan parameter tambahan ke kelas dengan menggunakan class Meta.

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

Satu-satunya yang saya temukan dalam dokumentasi Python adalah:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

Namun, saya tidak berpikir ini adalah hal yang sama.

miki725
sumber
6
Judul bertanya tentang meta Python, tetapi pertanyaan sepertinya menanyakan tentang meta Django - yang mana yang Anda tanyakan?
ckhan
10
@ckhan dia bingung karena keputusan absurd (IMO) untuk memanggil kelas bersarang "Meta", yang sangat menyesatkan; untuk pemula, tentang metaclasses Python, dan untuk pengguna yang lebih berpengalaman yang belum pernah melihatnya, tentang tujuannya a priori (alih-alih menggunakan atribut kelas atau metaclasses nyata)
JC Rocamonde

Jawaban:

234

Anda mengajukan pertanyaan tentang dua hal berbeda:

  1. Metakelas batin dalam model Django :

    Ini hanya wadah kelas dengan beberapa opsi (metadata) yang melekat pada model. Ini mendefinisikan hal-hal seperti izin yang tersedia, nama tabel database terkait, apakah model itu abstrak atau tidak, versi tunggal dan jamak nama dll.

    Penjelasan singkat ada di sini: Django docs: Models: Meta options

    Daftar opsi meta yang tersedia ada di sini: Django docs: Opsi Model Meta

    Untuk versi terbaru Django: Django docs: Opsi Model Meta

  2. Metaclass dalam Python :

    Deskripsi terbaik ada di sini: Apa itu metaclasses dalam Python?

Tadeck
sumber
3
Apakah kedua hal ini saling berkaitan? yaitu, apakah Metakelas dalam Django mencegah Anda menggunakan fitur metaclass builtin Python?
nnyby
10
@nnyby: Ada dua hal yang membuat hubungan antara kedua konsep ini: nama dan kebingungan yang dimiliki banyak pengguna (seperti yang dimiliki OP dalam pertanyaan aslinya). Saya percaya mengatasi bahwa kebingungan umum adalah keuntungan yang signifikan dari topi ini. Apakah kamu tidak setuju?
Tadeck
49

Memperluas jawaban Tangeck's Django di atas, penggunaan 'class Meta:' di Django juga hanya Python biasa.

Kelas internal adalah namespace yang nyaman untuk data bersama di antara instance kelas (maka nama Meta untuk 'metadata' tetapi Anda dapat menyebutnya apa saja yang Anda suka). Sementara di Django umumnya hanya konfigurasi hal-hal yang hanya baca, tidak ada yang menghentikan Anda mengubahnya:

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

Anda juga dapat menjelajahinya di Django misalnya:

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

Namun, di Django Anda lebih cenderung ingin menjelajahi _metaatribut yang merupakan Optionsobjek yang dibuat oleh model metaclassketika sebuah model dibuat. Di situlah Anda akan menemukan semua informasi 'meta' kelas Django. Dalam Django, Metahanya digunakan untuk meneruskan informasi ke dalam proses membuat _meta Optionsobjek.

Paul Whipp
sumber
Ini tidak berfungsi pada model yang ditentukan pengguna: >>> dari myapp.models impor MyModel >>> MyModel Traceback (panggilan terakhir terakhir): File "<console>", baris 1, di <module> AttributeError: ketik objek 'MyModel' tidak memiliki atribut 'meta'
bdf
2
Anda memerlukan garis bawah misalnyaMyUser.objects.get(pk=1)._meta
Paul Whipp
Benar, tapi itu tidak mengakses kelas Meta batin kelas Model. Itu mengakses opsi-opsi _meta untuk instance Model itu ... tampaknya tidak ada cara untuk mengakses kelas Meta bagian dalam itu sendiri. Kasus penggunaan bagi saya adalah subkelas kelas proxy MyModelProxy dari MyModel dengan cara di mana MyModelProxy dapat mewarisi kelas Meta batin MyModel.
bdf
Saya tidak sepenuhnya jelas tentang apa yang Anda maksud dengan 'inner Meta class' model tetapi Anda selalu dapat bekerja secara langsung dengan kelas instance misalnyatype(MyUser.objects.get(pk=1)).Meta
Paul Whipp
3
"namespace yang nyaman untuk data bersama di antara instance kelas" Baris itu melakukannya untuk saya.
MGP
22

ModelKelas Django secara khusus menangani memiliki atribut bernamaMeta yang merupakan kelas. Ini bukan hal Python umum.

Metaclasses Python sangat berbeda.

Amber
sumber
12
Saya pikir jawaban Anda tidak cukup jelas - dapatkah Anda menguraikan cara Metakerja kelas? Saya percaya OP bertanya secara spesifik tentang itu.
Tadeck
7

Jawaban yang mengklaim model Django Meta dan metaclasses "sangat berbeda" adalah jawaban yang menyesatkan.

Konstruksi objek kelas model Django (artinya objek yang mewakili definisi kelas itu sendiri; ya, kelas juga objek) memang dikendalikan oleh metaclass yang disebut ModelBase, Anda dapat melihat kode itu di sini:

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

Dan salah satu hal yang ModelBasedilakukan adalah membuat _metaatribut pada setiap model Django yang berisi mesin validasi, detail lapangan, save logic, dan sebagainya. Selama operasi ini, hal-hal yang ditentukan di bagian dalam modelMeta kelas dibaca dan digunakan dalam proses itu.

Jadi, sementara ya, dalam arti Metadan metaclasses adalah 'hal' yang berbeda, dalam mekanisme konstruksi model Django mereka terkait erat; memahami bagaimana mereka bekerja bersama akan memperdalam wawasan Anda menjadi keduanya sekaligus.

Ini mungkin menjadi sumber informasi yang bermanfaat untuk lebih memahami bagaimana model Django menggunakan metaclasses.

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

Dan ini mungkin membantu juga jika Anda ingin lebih memahami bagaimana benda bekerja secara umum.

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

jam
sumber
0

Dokumen Kelas Meta Dalam Dokumen metadata Model django ini adalah "apa pun yang bukan bidang", seperti opsi pemesanan (pemesanan), nama tabel database (db_table), atau nama tunggal dan jamak yang dapat dibaca manusia (verbose_name dan verbose_name_plural). Tidak ada yang diperlukan, dan menambahkan kelas Meta ke model sepenuhnya opsional. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Sujeet
sumber
0

Di Django, ini bertindak sebagai kelas konfigurasi dan menyimpan data konfigurasi di satu tempat !!

Rishi Chhabra
sumber