คลาส Meta ของ Django ทำงานอย่างไร?


191

ฉันใช้ Django class Metaซึ่งจะช่วยให้คนที่จะเพิ่มพารามิเตอร์พิเศษในชั้นเรียนโดยใช้

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

สิ่งเดียวที่ฉันพบในเอกสารของ Python คือ:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

อย่างไรก็ตามฉันไม่คิดว่านี่เป็นสิ่งเดียวกัน


6
ชื่อเรื่องถามเกี่ยวกับ Python meta แต่คำถามดูเหมือนว่าจะถามเกี่ยวกับ Django meta - คำถามใดที่คุณถาม
ckhan

10
@ckhan เขาสับสนเนื่องจากการตัดสินใจที่ไร้สาระ (IMO) เพื่อเรียกคลาส "Meta" ที่ซ้อนกันซึ่งทำให้เข้าใจผิดมาก สำหรับผู้เริ่มต้นเกี่ยวกับ metaclasses ของ Python และสำหรับผู้ใช้ที่มีประสบการณ์มากกว่าที่ไม่เคยเห็นมาก่อนเกี่ยวกับจุดประสงค์ของมันคือการให้ความสำคัญ (แทนการใช้คุณลักษณะคลาสหรือคลาสจริง)
JC Rocamonde

คำตอบ:


233

คุณกำลังถามคำถามเกี่ยวกับสองสิ่งที่แตกต่าง:

  1. Metaชั้นในในรุ่น Django :

    นี่เป็นเพียงคอนเทนเนอร์คลาสที่มีตัวเลือก (ข้อมูลเมตา) ติดอยู่กับโมเดล มันกำหนดสิ่งต่าง ๆ เช่นสิทธิ์ที่มีอยู่ชื่อตารางฐานข้อมูลที่เกี่ยวข้องไม่ว่าจะเป็นรูปแบบนามธรรมหรือไม่รุ่นชื่อเอกพจน์และพหูพจน์เป็นต้น

    คำอธิบายสั้น ๆ อยู่ที่นี่: Django docs: Models: Meta options

    รายการตัวเลือกเมตาที่มีอยู่ที่นี่: Django docs: ตัวเลือก Meta รุ่น

    สำหรับรุ่นล่าสุดของ Django: Django เอกสาร: ตัวเลือกรุ่น Meta

  2. Metaclass ใน Python :

    คำอธิบายที่ดีที่สุดอยู่ที่นี่: metaclasses ใน Python คืออะไร


3
สองสิ่งนี้เกี่ยวข้องกันหรือไม่? เช่นMetaคลาสภายในของ Django ป้องกันคุณจากการใช้คุณสมบัติ metaclass บิวท์อินของ Python หรือไม่?
nnyby

10
@ nnyby: มีสองสิ่งที่สร้างความสัมพันธ์ระหว่างแนวคิดทั้งสองนี้: ชื่อและความสับสนที่ผู้ใช้หลายคนมี (เช่น OP มีคำถามเดิม) ฉันเชื่อว่าการจัดการกับความสับสนทั่วไปเป็นข้อได้เปรียบที่สำคัญของ topi นี้ คุณไม่เห็นด้วยหรือ
Tadeck

49

เมื่อเพิ่มคำตอบ Django ของ Tadeck ด้านบนการใช้ 'class Meta:' ใน Django ก็เป็นเพียง Python ธรรมดาเช่นกัน

คลาสภายในเป็นเนมสเปซที่สะดวกสบายสำหรับข้อมูลที่ใช้ร่วมกันระหว่างอินสแตนซ์ของคลาส (ดังนั้นชื่อ Meta สำหรับ 'ข้อมูลเมตา' แต่คุณสามารถเรียกมันว่าอะไรก็ได้ที่คุณต้องการ) ขณะที่อยู่ใน Django มันเป็นเรื่องของการกำหนดค่าแบบอ่านอย่างเดียวไม่มีอะไรจะหยุดคุณเปลี่ยน:

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

คุณสามารถสำรวจใน Django ได้โดยตรงเช่น:

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

อย่างไรก็ตามใน Django คุณมีแนวโน้มที่จะต้องการสำรวจ_metaคุณสมบัติซึ่งเป็นOptionsวัตถุที่สร้างขึ้นโดยโมเดลmetaclassเมื่อสร้างโมเดล นั่นคือที่ที่คุณจะพบข้อมูล 'meta' ของ Django ทั้งหมด ใน Django Metaใช้เพื่อส่งผ่านข้อมูลไปยังกระบวนการสร้าง_meta Optionsวัตถุ


สิ่งนี้ใช้ไม่ได้กับรุ่นที่ผู้ใช้กำหนดเอง: >>> จาก myapp.models นำเข้า MyModel >>> MyModel.Meta Traceback (การโทรล่าสุดครั้งล่าสุด): ไฟล์ "<console>" บรรทัดที่ 1 ใน <module> AttributeError: type object 'MyModel' ไม่มีแอตทริบิวต์ 'meta'
bdf

2
คุณต้องการขีดล่างเช่นMyUser.objects.get(pk=1)._meta
Paul Whipp

ถูกต้อง แต่นั่นไม่ได้เข้าถึงคลาส Meta ภายในของ Model ที่เข้าถึงตัวเลือก _meta สำหรับอินสแตนซ์ของรุ่นนั้น ... ดูเหมือนจะไม่มีทางเข้าถึงคลาส Meta ภายในได้ กรณีการใช้งานสำหรับฉันกำลังซับคลาสคลาสพร็อกซี MyModelProxy จาก MyModel ในแบบที่ MyModelProxy สามารถสืบทอดคลาส Meta ภายในของ MyModel
bdf

ฉันไม่ชัดเจนในสิ่งที่คุณหมายถึงโดย 'รุ่น Meta ภายใน' ของโมเดล แต่คุณสามารถทำงานโดยตรงกับคลาสของอินสแตนซ์ได้เช่นtype(MyUser.objects.get(pk=1)).Meta
Paul Whipp

3
"เนมสเปซที่สะดวกสบายสำหรับข้อมูลที่ใช้ร่วมกันระหว่างคลาสอินสแตนซ์" บรรทัดนั้นทำเพื่อฉัน
MGP

22

Modelคลาสของ Django จัดการโดยเฉพาะอย่างยิ่งมีแอตทริบิวต์ชื่อMetaซึ่งเป็นคลาส มันไม่ใช่ของงูใหญ่ทั่วไป

Pac metaclasses แตกต่างอย่างสิ้นเชิง


12
ฉันคิดว่าคำตอบของคุณยังไม่ชัดเจน - คุณช่วยอธิบายเกี่ยวกับวิธีการMetaทำงานของชั้นเรียนได้ไหม? ฉันเชื่อว่า OP ถามเฉพาะเกี่ยวกับเรื่องนั้น
Tadeck

7

คำตอบที่อ้างว่าโมเดลของ Django Metaและ metaclasses นั้น "แตกต่างอย่างสิ้นเชิง" เป็นคำตอบที่ทำให้เข้าใจผิด

การสร้างวัตถุคลาสโมเดล Django (กล่าวคือวัตถุที่หมายถึงคำจำกัดความของคลาสนั้นใช่คลาสยังเป็นวัตถุ) ได้รับการควบคุมโดย metaclass ที่เรียกว่าModelBaseคุณจะเห็นรหัสที่นี่:

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

และหนึ่งในสิ่งที่ModelBaseจะทำคือการสร้าง_metaคุณลักษณะในทุกรุ่น Django ซึ่งมีเครื่องจักรการตรวจสอบรายละเอียดของฟิลด์บันทึกตรรกะและอื่น ๆ ในระหว่างการดำเนินการนี้เนื้อหาที่ระบุในMetaคลาสภายในของโมเดลจะถูกอ่านและใช้ภายในกระบวนการนั้น

ดังนั้นในขณะที่ใช่ในแง่หนึ่งMetaและ metaclasses แตกต่างกันคือ 'สิ่งของ' ภายในกลไกของการสร้างแบบจำลอง Django พวกเขามีความสัมพันธ์อย่างใกล้ชิด การทำความเข้าใจว่าพวกเขาทำงานร่วมกันอย่างไรจะทำให้คุณมีความเข้าใจลึกซึ้งยิ่งขึ้นในเวลาเดียวกัน

นี่อาจเป็นแหล่งข้อมูลที่มีประโยชน์เพื่อทำความเข้าใจว่าโมเดลของ Django ใช้ metaclasses อย่างไร

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

และสิ่งนี้อาจช่วยได้เช่นกันหากคุณต้องการเข้าใจวิธีการทำงานของวัตถุโดยทั่วไป

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


0

Inner Meta Class Document เอกสารของข้อมูลเมตาดาต้ารุ่น django นี้คือ“ อะไรก็ตามที่ไม่ใช่ฟิลด์” เช่นตัวเลือกการสั่งซื้อ (การสั่งซื้อ) ชื่อตารางฐานข้อมูล (db_table) หรือชื่อเอกพจน์และพหูพจน์ที่มนุษย์สามารถอ่านได้ (verbose_name และ verbose_name_plural) ไม่จำเป็นต้องมีและการเพิ่มคลาส Meta เข้ากับโมเดลเป็นทางเลือกอย่างสมบูรณ์ https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options


0

ใน Django มันทำหน้าที่เป็นคลาสการกำหนดค่าและเก็บข้อมูลการกำหนดค่าไว้ในที่เดียว !!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.