รับฟิลด์ของโมเดลใน Django


121

ด้วยโมเดล Django ฉันกำลังพยายามแสดงรายการฟิลด์ทั้งหมด ฉันเคยเห็นตัวอย่างการทำเช่นนี้โดยใช้แอตทริบิวต์แบบจำลอง _meta แต่เครื่องหมายขีดล่างข้างหน้าเมตาไม่ได้ระบุว่าแอตทริบิวต์ _meta เป็นแอตทริบิวต์ส่วนตัวและไม่ควรเข้าถึงโดยตรงหรือไม่ ... เนื่องจากรูปแบบของ _meta อาจเปลี่ยนแปลงได้ในอนาคตและไม่ใช่ API ที่เสถียร?

_meta เป็นข้อยกเว้นของกฎนี้หรือไม่ มีความเสถียรและพร้อมใช้งานหรือไม่หรือถือว่าเป็นการปฏิบัติที่ไม่ดีในการเข้าถึง หรือมีฟังก์ชั่นหรือวิธีอื่นในการวิเคราะห์ฟิลด์ของโมเดลโดยไม่ใช้แอตทริบิวต์ _meta หรือไม่? ด้านล่างนี้คือรายการลิงก์บางส่วนที่แสดงวิธีการดำเนินการโดยใช้แอตทริบิวต์ _meta

คำแนะนำใด ๆ ที่ชื่นชมมาก

django object get / set ฟิลด์

http://www.djangofoo.com/80/get-list-model-fields

วิธีการพิจารณาฟิลด์โมเดล django?


เป็นไปได้ที่จะซ้ำกันของDjango: รับรายการของฟิลด์รุ่น?
Anto

คำตอบ:


144

_metaมีความเป็นส่วนตัว แต่ค่อนข้างเสถียร มีความพยายามที่จะทำให้เป็นทางการจัดทำเอกสารและลบขีดล่างซึ่งอาจเกิดขึ้นก่อน 1.3 หรือ 1.4 ฉันคิดว่าจะมีความพยายามเพื่อให้แน่ใจว่าสิ่งต่าง ๆ สามารถใช้งานร่วมกันได้เพราะผู้คนจำนวนมากใช้มันอยู่แล้ว

หากคุณกังวลเป็นพิเศษเกี่ยวกับความเข้ากันได้ให้เขียนฟังก์ชันที่ใช้โมเดลและส่งคืนฟิลด์ ซึ่งหมายความว่าหากมีการเปลี่ยนแปลงในอนาคตคุณจะต้องเปลี่ยนฟังก์ชันเดียวเท่านั้น

def get_model_fields(model):
    return model._meta.fields

ฉันเชื่อว่านี่จะส่งคืนรายการFieldวัตถุ getattr(instance, field.name)ที่จะได้รับค่าของแต่ละเขตข้อมูลจากตัวอย่างการใช้

อัปเดต: ผู้สนับสนุน Django กำลังทำงานกับ API เพื่อแทนที่ออบเจ็กต์ _Meta เป็นส่วนหนึ่งของ Google Summer of Code ดู:
- https://groups.google.com/forum/#!topic/django-developers/hD4roZq0wyk
- https://code.djangoproject.com/wiki/new_meta_api


45
คุณควรตระหนักถึงความจริงของเขาด้วยว่าหากคุณต้องการฟิลด์แบบกลุ่มต่อกลุ่มคุณจำเป็นต้องเข้าถึงmodel._meta.many_to_many!
Bernhard Vallant

1
ขอบคุณ Will. น่ารู้ว่ามีคนอื่นใช้ _meta เช่นกัน ฉันชอบความคิดของการมีฟังก์ชัน Wrapper Lazerscience ขอบคุณเช่นกัน นานาน่ารู้มีวิธีการที่ดีในการรับฟิลด์ many_to_many โจ
โจ

3
django/core/management/commands/loaddata.pyใช้ _meta เพื่อเดินตามโครงสร้างของแอพโมเดลและฟิลด์ รูปแบบที่ดีในการปฏิบัติตาม ... และคุณสามารถเดิมพันได้ว่าเป็น "วิธีทางการ"
เตาอบ

2
หากคุณใช้คีย์ต่างประเทศทั่วไปคุณควรตรวจสอบด้วย_meta.virtual_fields
andrei1089


97

ฉันรู้ว่าโพสต์นี้ค่อนข้างเก่า แต่ฉันแค่สนใจที่จะบอกทุกคนที่กำลังค้นหาสิ่งเดียวกันว่ามี API สาธารณะและเป็นทางการสำหรับทำสิ่งนี้: get_fields()และget_field()

การใช้งาน:

fields = model._meta.get_fields()
my_field = model._meta.get_field('my_field')

https://docs.djangoproject.com/en/1.8/ref/models/meta/


6
นี่เป็นคำตอบที่ถูกต้องสำหรับ django เวอร์ชันใหม่กว่า
chhantyal


3
คำถามหนึ่ง: หากเป็น "สาธารณะและเป็นทางการ" ทำไมถึงยังอยู่ภายใต้_meta?
krubo

9

ตอนนี้มีวิธีพิเศษ - get_fields ()

    >>> from django.contrib.auth.models import User
    >>> User._meta.get_fields()

ยอมรับสองพารามิเตอร์ที่สามารถใช้เพื่อควบคุมฟิลด์ที่จะส่งคืน:

  • include_parents

    True ตามค่าเริ่มต้น รวมฟิลด์ซ้ำ ๆ ที่กำหนดไว้ในคลาสพาเรนต์ หากตั้งค่าเป็น False get_fields () จะค้นหาเฉพาะฟิลด์ที่ประกาศโดยตรงในโมเดลปัจจุบัน ฟิลด์จากโมเดลที่สืบทอดโดยตรงจากโมเดลนามธรรมหรือคลาสพร็อกซีจะถือว่าเป็นแบบโลคัลไม่ใช่บนพาเรนต์

  • include_hidden

    เป็นเท็จโดยปริยาย หากตั้งค่าเป็น True get_fields () จะรวมฟิลด์ที่ใช้เพื่อสำรองฟังก์ชันการทำงานของฟิลด์อื่น นอกจากนี้ยังรวมถึงช่องใด ๆ ที่มี related_name (เช่น ManyToManyField หรือ ForeignKey) ที่ขึ้นต้นด้วย“ +”


9

get_fields()ส่งคืน a tupleและแต่ละองค์ประกอบเป็นModel fieldประเภทซึ่งไม่สามารถใช้เป็นสตริงได้โดยตรง ดังนั้นfield.nameจะส่งคืนชื่อฟิลด์

my_model_fields = [field.name for field in MyModel._meta.get_fields()]
โค้ดด้านบนจะส่งคืนรายการที่มีตัวอย่างชื่อฟิลด์ทั้งหมด


In [11]: from django.contrib.auth.models import User

In [12]: User._meta.get_fields()
Out[12]: 
(<ManyToOneRel: admin.logentry>,
 <django.db.models.fields.AutoField: id>,
 <django.db.models.fields.CharField: password>,
 <django.db.models.fields.DateTimeField: last_login>,
 <django.db.models.fields.BooleanField: is_superuser>,
 <django.db.models.fields.CharField: username>,
 <django.db.models.fields.CharField: first_name>,
 <django.db.models.fields.CharField: last_name>,
 <django.db.models.fields.EmailField: email>,
 <django.db.models.fields.BooleanField: is_staff>,
 <django.db.models.fields.BooleanField: is_active>,
 <django.db.models.fields.DateTimeField: date_joined>,
 <django.db.models.fields.related.ManyToManyField: groups>,
 <django.db.models.fields.related.ManyToManyField: user_permissions>)

In [13]: [field.name for field in User._meta.get_fields()]
Out[13]: 
['logentry',
 'id',
 'password',
 'last_login',
 'is_superuser',
 'username',
 'first_name',
 'last_name',
 'email',
 'is_staff',
 'is_active',
 'date_joined',
 'groups',
 'user_permissions']

ตอบโจทย์มาก! ขอบคุณ!
Tms91

8

นี่คือสิ่งที่ Django ทำเองเมื่อสร้างแบบฟอร์มจากแบบจำลอง มันใช้แอตทริบิวต์ _meta แต่ตามที่ Bernhard ตั้งข้อสังเกตมันใช้ทั้ง _meta.fields และ _meta.many_to_many ดูที่ django.forms.models.fields_for_model นี่คือวิธีที่คุณสามารถทำได้:

opts = model._meta
for f in sorted(opts.fields + opts.many_to_many):
    print '%s: %s' % (f.name, f)

4

ฟิลด์โมเดลที่มีโดย _meta จะแสดงรายการในหลายตำแหน่งเป็นรายการของอ็อบเจ็กต์ฟิลด์ที่เกี่ยวข้อง มันอาจจะง่ายกว่าที่จะใช้เป็นพจนานุกรมโดยที่คีย์เป็นชื่อฟิลด์

ในความคิดของฉันนี่เป็นวิธีที่ไม่ลดทอนและแสดงออกมากที่สุดในการรวบรวมและจัดระเบียบวัตถุฟิลด์โมเดล:

def get_model_fields(model):
  fields = {}
  options = model._meta
  for field in sorted(options.concrete_fields + options.many_to_many + options.virtual_fields):
    fields[field.name] = field
  return fields

(ดูตัวอย่างการใช้งานนี้ใน django.forms.models.fields_for_model)


2
คุณอาจต้องการแนบโค้ดของคุณพร้อมคำอธิบายสั้น ๆ ว่ากำลังทำอะไรอยู่
Bas van Dijk

2

แล้วอันนี้ละ.

fields = Model._meta.fields

1
ฉันคิดว่าอาจมีคนต้องการเข้าถึงคุณสมบัติของฟิลด์ นอกจากนี้ตามที่ชี้ให้เห็นในคำตอบก่อนหน้านี้มีและmany_to_many virtual_fields
Jocke

@Jocke ใช่มั้ย อาจจำเป็นต้องเข้าถึงแอตทริบิวต์อื่น แก้ไขคำตอบแล้ว
JDE876

2

ตามเอกสาร django 2.2 คุณสามารถใช้:

ในการรับทุกช่อง: Model._meta.get_fields()

ในการรับแต่ละฟิลด์: Model._meta.get_field('field name')

อดีต Session._meta.get_field('expire_date')


1

หากคุณต้องการนี้สำหรับผู้ดูแลระบบเว็บไซต์นอกจากนี้ยังมีModelAdmin.get_fieldsวิธีการ ( เอกสาร ) ซึ่งผลตอบแทนของชื่อเขตliststrings

ตัวอย่างเช่น:

class MyModelAdmin(admin.ModelAdmin):
    # extending change_view, just as an example
    def change_view(self, request, object_id=None, form_url='', extra_context=None):
        # get the model field names
        field_names = self.get_fields(request)
        # use the field names
        ...

0

อีกวิธีหนึ่งคือเพิ่มฟังก์ชันให้กับโมเดลและเมื่อคุณต้องการแทนที่วันที่คุณสามารถเรียกใช้ฟังก์ชันได้

class MyModel(models.Model):
    name = models.CharField(max_length=256)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    def set_created_date(self, created_date):
        field = self._meta.get_field('created')
        field.auto_now_add = False
        self.created = created_date

    def set_modified_date(self, modified_date):
        field = self._meta.get_field('modified')
        field.auto_now = False
        self.modified = modified_date

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