Django: मॉडल क्षेत्रों की सूची प्राप्त करें?


198

मैंने एक Userवर्ग को परिभाषित किया है जो (अंततः) से विरासत में मिला है models.Model। मैं इस मॉडल के लिए परिभाषित सभी क्षेत्रों की एक सूची प्राप्त करना चाहता हूं। उदाहरण के लिए, phone_number = CharField(max_length=20)। मूल रूप से, मैं कुछ भी प्राप्त करना चाहता हूं जो Fieldवर्ग से विरासत में मिला है ।

मुझे लगा कि मैं इसका लाभ उठाकर उन्हें पुनः प्राप्त कर सकूंगा inspect.getmembers(model), लेकिन इस सूची में इनमें से कोई भी क्षेत्र शामिल नहीं है। ऐसा लगता है कि Django ने पहले ही वर्ग की पकड़ हासिल कर ली है और अपनी सभी जादुई विशेषताओं को जोड़ा और वास्तव में परिभाषित किया गया है। तो ... मैं इन क्षेत्रों को कैसे प्राप्त कर सकता हूं? संभवतः उनके पास अपने स्वयं के आंतरिक उद्देश्यों के लिए उन्हें पुनः प्राप्त करने का एक कार्य है?


यह मदद कर सकता है, pypi.python.org/pypi/django-inspect-model/0.5
पाओलो

जवाबों:


48

जैसा कि अधिकांश उत्तर पुराने हैं, मैं आपको Django 2.2 पर अपडेट करने की कोशिश करूंगा। यहां पोस्ट- आपके एप्लिकेशन (पोस्ट, ब्लॉग, दुकान, आदि)

1) मॉडल लिंक से: https://docs.djangoproject.com/en/2.2/ref/models/meta/

from posts.model import BlogPost

all_fields = BlogPost._meta.fields
#or
all_fields = BlogPost._meta.get_fields()

ध्यान दें कि:

all_fields=BlogPost._meta.get_fields()

कुछ रिश्ते भी मिलेंगे, जो, उदाहरण के लिए: आप एक दृश्य में प्रदर्शित नहीं कर सकते।
जैसा कि मेरे मामले में:

Organisation._meta.fields
(<django.db.models.fields.AutoField: id>, <django.db.models.fields.DateField: created>...

तथा

Organisation._meta.get_fields()
(<ManyToOneRel: crm.activity>, <django.db.models.fields.AutoField: id>, <django.db.models.fields.DateField: created>...

2) उदाहरण से

from posts.model import BlogPost

bp = BlogPost()
all_fields = bp._meta.fields

3) मूल मॉडल से

मान लीजिए कि हमारे पास मूल मॉडल के रूप में पोस्ट है और आप एक सूची में सभी फ़ील्ड देखना चाहते हैं, और मूल फ़ील्ड को केवल-संपादन मोड में पढ़ा जाना चाहिए।

from django.contrib import admin
from posts.model import BlogPost 

@admin.register(BlogPost)
class BlogPost(admin.ModelAdmin):
    all_fields = [f.name for f in Organisation._meta.fields]
    parent_fields = BlogPost.get_deferred_fields(BlogPost)

    list_display = all_fields
    read_only = parent_fields

1
मैं इसे सही मानूंगा और इसे नए उत्तर के रूप में स्वीकार करूंगा। अद्यतन के लिए धन्यवाद!
एमपैन

@mpen यह सबसे अच्छा तरीका है या सबसे pythonic का दावा है, लेकिन नीचे होगा / प्राप्त करना चाहिए मूल्यों यू एक दृश्य में प्रदर्शित करना चाहते हैं, तो एक HTML तालिका के हेडर अगर आप करेंगे। जैसा कि get_fields () एक tuple लौटाता है, आप उस पर पुनरावृति कर सकते हैं और मान प्राप्त कर सकते हैं जो appname.Model.field_name जैसा दिखता है, नीचे दिए गए मानों को दूसरे बिंदु से साफ़ करता है, इसमें वह मामला भी शामिल है जिसमें फ़ील्ड नाम के रूप में एक अंडरस्कोर का उपयोग किया गया था साथ ही उन्हें एक शीर्षक दें, इसलिए प्रत्येक अद्वितीय स्थिति के लिए आवश्यकतानुसार संशोधित करें। clean_field_names = [str(h).split('.')[2].replace("_", " ").title() for h in all_fields]
अलेजांद्रो सुआरेज

1
उदाहरण से उदाहरण होना चाहिए:all_fields = bp._meta.fields
जॉर्ज केटलबोरो

@GeorgeKettleborough मैं इस बिंदु को देखता हूं। क्या यह कक्षा से सीधे भी काम नहीं करता है? परीक्षण करने के लिए उदाहरण नहीं है। वैसे भी उदाहरण उदाहरण के लिए है, इसलिए यह bp या कम से कम bp .__ class__ से होना चाहिए
Maks

294

Django संस्करण 1.8 और बाद में:

आपको उपयोग करना चाहिए get_fields():

[f.name for f in MyModel._meta.get_fields()]

get_all_field_names()विधि है Django 1.8 से शुरू पदावनत और 1.10 में निकाल दिया जाएगा

ऊपर लिंक किया गया प्रलेखन पृष्ठ पूरी तरह से पीछे की ओर संगत-संगत कार्यान्वयन प्रदान करता है get_all_field_names(), लेकिन अधिकांश उद्देश्यों के लिए पिछले उदाहरण को ठीक काम करना चाहिए।


1.8 से पहले Django संस्करण:

model._meta.get_all_field_names()

यह ट्रिक काम आना चाहिए।

इसके लिए एक वास्तविक मॉडल उदाहरण की आवश्यकता है। यदि आपके पास सब-सब का एक उपवर्ग है django.db.models.Model, तो आपको कॉल करना चाहिएmyproject.myapp.models.MyModel._meta.get_all_field_names()


11
वस्तुओं को भी चाहते थे, केवल उनके नामों को नहीं। model._meta.fieldsहालांकि यह उपलब्ध प्रतीत होता है , और field.nameऐसा लगता है कि उनके नाम पुनर्प्राप्त करने योग्य हैं । मुझे उम्मीद है कि इस जानकारी को पुनः प्राप्त करने का यह सबसे स्थिर तरीका है :)
म्पेन

2
पूरी तरह से निश्चित नहीं। अंडरस्कोर यह इंगित करता है कि यह एक आंतरिक एपीआई है, यह अच्छा होगा यदि Django के लोगों ने इसे वास्तव में सार्वजनिक पद्धति पर कॉल करने के लिए प्रचारित किया django.db.models.Model। मैं इसे
खोदूँगा

2
मुझे लगता है कि यह _metaविशेषता के माध्यम से कर रहा है एक ही रास्ता है ... इसके अलावा _meta.many_to_manyManyToMany क्षेत्रों के लिए देखो !
बर्नहार्ड वलंट

3
यह एक अच्छा समाधान है लेकिन इस पद्धति में रिवर्स फॉरेनके जैसे रिवर्स रिलेशन फ़ील्ड शामिल हैं और वे बिल्कुल "फ़ील्ड" नहीं हैं। किसी को पता है कि वास्तविक फ़ील्ड्स को कैसे अलग करना है?
वारिदिस

2
@rossipedia: बस यह देखते हुए कि ._meta एपीआई सार्वजनिक है (हालांकि यह, निजी होने के लिए शायद जब इस उत्तर पहले लिखा गया था इस्तेमाल किया): docs.djangoproject.com/en/1.8/ref/models/meta/...
निक एस

76

इस get_all_related_fields()विधि का उल्लेख 1.8 में किया गया है । अब से यह पर है get_fields()

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

1
यह अब स्वीकृत उत्तर होना चाहिए। प्रवृत्ति, और बिंदु तक।
अरनौद पी

हां यह जवाब है।
एरिक

55

मुझे लगता है कि यह django मॉडल को काफी मददगार है:

def __iter__(self):
    for field_name in self._meta.get_all_field_names():
        value = getattr(self, field_name, None)
        yield (field_name, value)

इससे आप कर सकते हैं:

for field, val in object:
    print field, val

2
विदेशी के बारे में क्या? मेरे पास इस तरह की त्रुटियां हैंdjango.db.models.fields.related.RelatedObjectDoesNotExist: CustomModel has no custom_attribute.
SAKrisT

ForeignKeyमेरे लिए ठीक है। हालांकि, चुपचाप सभी अपवादों को पकड़ना एक विरोधी पैटर्न है। पकड़ने के लिए बहुत बेहतर है AttributeError, या कम से कम लॉग इन करें कि कुछ अपवाद चुपचाप निगल लिया गया था।
सद्रथ्रियन -

1
self._meta.get_all_field_names()हटा दिया गया है और हटा दिया गया है। आप कुछ का उपयोग कर सकते हैं for field in self._meta.get_fields()और फिरyield (field.name, field.value_from_object(self))
19

13

यह ट्रिक करता है। मैं केवल इसे Django 1.7 में परीक्षण करता हूं।

your_fields = YourModel._meta.local_fields
your_field_names = [f.name for f in your_fields]

Model._meta.local_fieldsकई-से-कई फ़ील्ड नहीं होते हैं। आपको उनका उपयोग करना चाहिए Model._meta.local_many_to_many


10

यह स्पष्ट नहीं है कि आपके पास स्वयं या वर्ग का एक उदाहरण है और फ़ील्ड को पुनः प्राप्त करने का प्रयास कर रहा है, लेकिन किसी भी तरह, निम्नलिखित कोड पर विचार करें

एक उदाहरण का उपयोग करना

instance = User.objects.get(username="foo")
instance.__dict__ # returns a dictionary with all fields and their values
instance.__dict__.keys() # returns a dictionary with all fields
list(instance.__dict__.keys()) # returns list with all fields

कक्षा का उपयोग करना

User._meta.__dict__.get("fields") # returns the fields

# to get the field names consider looping over the fields and calling __str__()
for field in User._meta.__dict__.get("fields"):
    field.__str__() # e.g. 'auth.User.id'

10
def __iter__(self):
    field_names = [f.name for f in self._meta.fields]
    for field_name in field_names:
        value = getattr(self, field_name, None)
        yield (field_name, value)

इसमें मेरे लिए काम किया django==1.11.8


8

MyModel._meta.get_all_field_names()था पदावनत कई संस्करण पीठ और हटाया Django 1.10 में।

यहाँ डॉक्स से पीछे-संगत सुझाव दिया गया है :

from itertools import chain

list(set(chain.from_iterable(
    (field.name, field.attname) if hasattr(field, 'attname') else (field.name,)
    for field in MyModel._meta.get_fields()
    # For complete backwards compatibility, you may want to exclude
    # GenericForeignKey from the results.
    if not (field.many_to_one and field.related_model is None)
)))

6

बस जोड़ने के लिए, मैं आत्म वस्तु का उपयोग कर रहा हूं, यह मेरे लिए काम कर रहा है:

[f.name for f in self.model._meta.get_fields()]

5

कम से कम Django 1.9.9 के साथ - वर्तमान में मैं जिस संस्करण का उपयोग कर रहा हूं - ध्यान दें कि .get_fields()वास्तव में किसी भी विदेशी मॉडल को "एक क्षेत्र के रूप में" मानता है, जो समस्याग्रस्त हो सकता है। आप कहें:

class Parent(models.Model):
    id = UUIDField(primary_key=True)

class Child(models.Model):
    parent = models.ForeignKey(Parent)

यह इस प्रकार है कि

>>> map(lambda field:field.name, Parent._model._meta.get_fields())
['id', 'child']

जबकि, जैसा @Rockallite द्वारा दिखाया गया है

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']

4

इसलिए इस पद को पाने से पहले, मैंने सफलतापूर्वक इसे काम करने के लिए पाया।

Model._meta.fields

यह समान रूप से काम करता है

Model._meta.get_fields()

मुझे यकीन नहीं है कि परिणामों में अंतर क्या है, अगर वहाँ एक है। मैंने इस लूप को चलाया और वही आउटपुट मिला।

for field in Model._meta.fields:
    print(field.name)

-2

क्यों नहीं बस का उपयोग करें कि:

manage.py inspectdb

उदाहरण आउटपुट:

class GuardianUserobjectpermission(models.Model):
    id = models.IntegerField(primary_key=True)  # AutoField?
    object_pk = models.CharField(max_length=255)
    content_type = models.ForeignKey(DjangoContentType, models.DO_NOTHING)
    permission = models.ForeignKey(AuthPermission, models.DO_NOTHING)
    user = models.ForeignKey(CustomUsers, models.DO_NOTHING)

    class Meta:
        managed = False
        db_table = 'guardian_userobjectpermission'
        unique_together = (('user', 'permission', 'object_pk'),)

1
यह सवाल का जवाब नहीं है।
शैने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.