एक Django ModelAdmin में "list_display" कर सकते हैं विदेश के खेतों का प्रदर्शन?


296

मेरे पास एक Personमॉडल है जिसके पास एक विदेशी कुंजी संबंध है Book, जिसमें कई फ़ील्ड हैं, लेकिन मैं सबसे अधिक चिंतित हूं author(एक मानक चारफिल्ड)।

कहा जा रहा है कि, मेरे PersonAdminमॉडल में, मैं book.authorउपयोग करके प्रदर्शित करना चाहूंगा list_display:

class PersonAdmin(admin.ModelAdmin):
    list_display = ['book.author',]

मैंने ऐसा करने के लिए सभी स्पष्ट तरीकों की कोशिश की है, लेकिन कुछ भी काम नहीं करता है।

कोई सुझाव?

जवाबों:


472

एक अन्य विकल्प के रूप में, आप इस तरह दिख सकते हैं:

class UserAdmin(admin.ModelAdmin):
    list_display = (..., 'get_author')

    def get_author(self, obj):
        return obj.book.author
    get_author.short_description = 'Author'
    get_author.admin_order_field = 'book__author'

क्या दोनों को नहीं होना चाहिए get_author, क्योंकि जो स्ट्रिंग आप वापस लौट रहे हैं (और संक्षिप्त विवरण) वास्तव में संदर्भ है? या स्ट्रिंग प्रारूप तर्क को बदल दें obj.book.reviews?
कार्ल जी

1
@AnatoliyArkhipov, एक तरीका है (आतंक के जवाब पर आधारित )। मैंने पहले ही इस उत्तर में कोड अपडेट कर दिया है।
डेनिल्सन सा मैया जूल

तुम सिर्फ author = ForeignKey(Author)किताब मॉडल में क्यों नहीं कर सकते , और फिर list_display = ('author')?
अलियास ५१

3
यह व्यवस्थापक में प्रदर्शित प्रति पंक्ति एक क्वेरी का कारण बनता है :(
मार्सेलम

1
@marcelm यह है कि क्या select_relatedहै के लिए get_queryset()के UserAdminओवरराइट किया जा करना होगा।
इंटरडिस्ट जूल

142

उपरोक्त सभी शानदार जवाबों के बावजूद और मुझे Django के लिए नया होने के कारण, मैं अभी भी अटका हुआ था। यहाँ एक बहुत ही नौसिखिया परिप्रेक्ष्य से मेरी व्याख्या है।

models.py

class Author(models.Model):
    name = models.CharField(max_length=255)

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=255)

admin.py (गलत तरीका) - आपको लगता है कि यह संदर्भ के लिए 'model__field' का उपयोग करके काम करेगा, लेकिन ऐसा नहीं है

class BookAdmin(admin.ModelAdmin):
    model = Book
    list_display = ['title', 'author__name', ]

admin.site.register(Book, BookAdmin)

admin.py (Correct Way) - यह है कि आप एक विदेशी कुंजी का नाम Django रास्ता कैसे देखें

class BookAdmin(admin.ModelAdmin):
    model = Book
    list_display = ['title', 'get_name', ]

    def get_name(self, obj):
        return obj.author.name
    get_name.admin_order_field  = 'author'  #Allows column order sorting
    get_name.short_description = 'Author Name'  #Renames column head

    #Filtering on side - for some reason, this works
    #list_filter = ['title', 'author__name']

admin.site.register(Book, BookAdmin)

अतिरिक्त संदर्भ के लिए, यहां Django मॉडल लिंक देखें


3
ऑर्डर फ़ील्ड के लिए यह = 'author__name' नहीं होना चाहिए?
यूंती

2
यह पूरी तरह से काम करता है, हालांकि मैं अनिश्चित हूं कि क्यों। objहै BookAdmin?
स्टीवन चर्च

वाह। इसे खोजने के लिए मुझे वेब पर एक घंटा लगा। यह Django प्रलेखन में बहुत स्पष्ट किया जाना चाहिए
सत्रह

67

बाकी की तरह, मैं भी कॉलबेल के साथ गया था। लेकिन उनके पास एक नकारात्मक पहलू है: डिफ़ॉल्ट रूप से, आप उन पर ऑर्डर नहीं कर सकते। सौभाग्य से, इसके लिए एक समाधान है:

Django> = 1.8

def author(self, obj):
    return obj.book.author
author.admin_order_field  = 'book__author'

Django <1.8

def author(self):
    return self.book.author
author.admin_order_field  = 'book__author'

विधि हस्ताक्षर होना चाहिएdef author(self, obj):
sheats

वापस जब मैंने टिप्पणी की तो यह मामला नहीं था, लेकिन ऐसा प्रतीत होता है कि संस्करण 1.8 के बाद से यह विधि उस वस्तु को पास कर देती है। मैंने अपना उत्तर अपडेट कर दिया है।
आरजेन

46

कृपया ध्यान दें कि get_authorफ़ंक्शन को जोड़ने से व्यवस्थापक में list_display धीमा हो जाएगा, क्योंकि प्रत्येक व्यक्ति को दिखाने से SQL क्वेरी होगी।

इससे बचने के लिए, आपको get_querysetउदाहरण के लिए पर्सनडमिन में विधि को संशोधित करना होगा :

def get_queryset(self, request):
    return super(PersonAdmin,self).get_queryset(request).select_related('book')

पहले: 36.02ms में 73 प्रश्न (एडमिन में 67 डुप्लिकेट प्रश्न)

के बाद: 10.81ms में 6 प्रश्न


3
यह वास्तव में महत्वपूर्ण है और इसे हमेशा लागू किया जाना चाहिए
xleon

यह वास्तव में महत्वपूर्ण है। वैकल्पिक रूप से, यदि किसी को __str__मार्ग से नीचे जाना है , तो बस विदेशी को जोड़ें list_displayऔरlist_select_related
स्क्रैच'न'पार्ट

22

प्रलेखन के अनुसार, आप केवल __unicode__एक विदेशी का प्रतिनिधित्व प्रदर्शित कर सकते हैं :

http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-display

अजीब लगता है कि यह 'book__author'शैली प्रारूप का समर्थन नहीं करता है जो डीबी एपीआई में हर जगह उपयोग किया जाता है।

पता चलता है कि इस सुविधा के लिए एक टिकट है , जिसे W't Fix के रूप में चिह्नित किया गया है।


11
@ सच में? ऐसा प्रतीत होता है कि टिकट वॉन्टिक्स के रूप में सेट रहता है। यह (Django 1.3) या तो काम करने के लिए प्रकट नहीं होता है
डेव

1.11 अभी भी मौजूद नहीं है। एक दर्जन वर्षों के लिए django कर रहा है और मुझे यह कभी याद नहीं है :(
हारून मैकमिलन

12

मैंने सिर्फ एक स्निपेट पोस्ट किया है जो व्यवस्थापक बनाता है ।odelAdmin '__' सिंटैक्स का समर्थन करता है:

http://djangosnippets.org/snippets/2887/

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

class PersonAdmin(RelatedFieldAdmin):
    list_display = ['book__author',]

यह मूल रूप से अन्य उत्तरों में वर्णित एक ही काम कर रहा है, लेकिन यह स्वचालित रूप से (1) सेटिंग का ख्याल रखता है admin_order_field (2) सेटिंग short_description और (3) क्वेरी को संशोधित करने के लिए प्रत्येक पंक्ति के लिए डेटाबेस हिट से बचने के लिए।


मैं इस विचार को बहुत पसंद करता हूं, लेकिन यह हाल ही में django verions के साथ अब काम नहीं करता है:AttributeError: type object 'BaseModel' has no attribute '__metaclass__'
विन्सेन्ट वैन लीउवेन

10

आप एक कॉल करने योग्य का उपयोग करके सूची प्रदर्शन में जो चाहें दिखा सकते हैं। यह इस तरह दिखेगा:

def book_author (ऑब्जेक्ट):
  वापसी object.book.author

वर्ग के व्यक्ति
  list_display = [book_author,]

यह एक स्थितियों के लिए अच्छा है, जहां बहुत सारे विभिन्न मॉडल अक्सर एक ही विशेषता को कहते हैं; क्या यह 1.3+ में समर्थित है?
कागली-सान

3
इस बारे में समस्या अंत में किए गए एसक्यूएल प्रश्नों की मात्रा है। सूची में प्रत्येक वस्तु के लिए, यह एक प्रश्न बना देगा। यही कारण है कि 'field__attribute' बहुत उपयोगी होगा, क्योंकि निश्चित रूप से Django केवल एक SQL क्वेरी के लिए होगा। अजीब बात है कि इसका कोई समर्थन पहले से ही नहीं है।
एमिलर

7

यह पहले से ही स्वीकार कर लिया गया है, लेकिन अगर वहाँ किसी भी अन्य dummies वहाँ (मेरे जैसे) है कि तुरंत वर्तमान में स्वीकार किए जाते हैं जवाब से नहीं मिला , यहाँ थोड़ा और अधिक विस्तार है।

मॉडल वर्ग ForeignKeyको इसके __unicode__भीतर एक विधि की आवश्यकता से संदर्भित है , जैसे कि:

class Category(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

यह मेरे लिए अंतर बना, और उपरोक्त परिदृश्य पर लागू होना चाहिए। यह Django 1.0.2 पर काम करता है।


4
अजगर 3 पर यह होगा def __str__(self):
मार्टलार्क

5

यदि आपके पास उपयोग करने के लिए बहुत सारे संबंध विशेषता फ़ील्ड list_displayहैं और प्रत्येक के लिए एक फ़ंक्शन (और यह विशेषता है) नहीं बनाना चाहते हैं, तो एक गंदगी लेकिन सरल समाधान ModelAdminइंस्टैस __getattr__विधि को ओवरराइड करेगा , मक्खी पर कॉलबल्स का निर्माण करेगा:

class DynamicLookupMixin(object):
    '''
    a mixin to add dynamic callable attributes like 'book__author' which
    return a function that return the instance.book.author value
    '''

    def __getattr__(self, attr):
        if ('__' in attr
            and not attr.startswith('_')
            and not attr.endswith('_boolean')
            and not attr.endswith('_short_description')):

            def dyn_lookup(instance):
                # traverse all __ lookups
                return reduce(lambda parent, child: getattr(parent, child),
                              attr.split('__'),
                              instance)

            # get admin_order_field, boolean and short_description
            dyn_lookup.admin_order_field = attr
            dyn_lookup.boolean = getattr(self, '{}_boolean'.format(attr), False)
            dyn_lookup.short_description = getattr(
                self, '{}_short_description'.format(attr),
                attr.replace('_', ' ').capitalize())

            return dyn_lookup

        # not dynamic lookup, default behaviour
        return self.__getattribute__(attr)


# use examples    

@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin, DynamicLookupMixin):
    list_display = ['book__author', 'book__publisher__name',
                    'book__publisher__country']

    # custom short description
    book__publisher__country_short_description = 'Publisher Country'


@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin, DynamicLookupMixin):
    list_display = ('name', 'category__is_new')

    # to show as boolean field
    category__is_new_boolean = True

यहाँ पर जिस्ट के रूप में

कॉल करने योग्य विशिष्ट विशेषताओं जैसे booleanऔर विशेषताओं, जैसे और short_descriptionपरिभाषित किया जाना चाहिए ।ModelAdminbook__author_verbose_name = 'Author name'category__is_new_boolean = True

कॉल करने योग्य admin_order_fieldविशेषता स्वचालित रूप से परिभाषित होती है।

Django को प्रासंगिकModelAdmin प्रश्नों से बचने के लिए list_select_related विशेषता का उपयोग करने के लिए मत भूलना ।


1
बस एक Django 2.2 स्थापित के साथ यह कोशिश की और यह मेरे लिए बहुत अच्छा काम किया, जबकि अन्य दृष्टिकोण जो भी कारण के लिए नहीं किया। ध्यान दें कि आजकल आपको फंक्शनलूल या कहीं और से आयात करने की आवश्यकता है ...
पॉल ब्रैकिन

5

PyPI में उपलब्ध पैकेज का उपयोग करने के लिए एक बहुत ही आसान है जो कि ठीक से संभालता है: django- संबंधित-व्यवस्थापक । आप GitHub में कोड भी देख सकते हैं

इसका उपयोग करके, आप जो हासिल करना चाहते हैं वह उतना ही सरल है:

class PersonAdmin(RelatedFieldAdmin):
    list_display = ['book__author',]

दोनों लिंक में इंस्टॉलेशन और उपयोग का पूरा विवरण होता है इसलिए मैं उन्हें बदलने की स्थिति में यहां पेस्ट नहीं करूंगा।

एक साइड नोट के रूप में, यदि आप पहले से ही इसके अलावा कुछ उपयोग कर रहे हैं model.Admin(जैसे मैं SimpleHistoryAdminइसके बजाय उपयोग कर रहा था ), तो आप यह कर सकते हैं class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin):।


getter_for_related_field 1.9 में काम नहीं करता है, इसलिए यह उन लोगों के लिए सबसे अच्छा विकल्प नहीं है जो अनुरूपण पसंद करते हैं।
ग्रिमेल

4

यदि आप इसे इनलाइन करने की कोशिश करते हैं, तो आप तब तक सफल नहीं होंगे जब तक कि:

अपनी इनलाइन में:

class AddInline(admin.TabularInline):
    readonly_fields = ['localname',]
    model = MyModel
    fields = ('localname',)

अपने मॉडल (MyModel) में:

class MyModel(models.Model):
    localization = models.ForeignKey(Localizations)

    def localname(self):
        return self.localization.name

-1

AlexRobbins के उत्तर ने मेरे लिए काम किया, सिवाय इसके कि पहली दो पंक्तियों को मॉडल में होने की आवश्यकता है (शायद यह मान लिया गया था?), और स्वयं को संदर्भित करना चाहिए:

def book_author(self):
  return self.book.author

तब व्यवस्थापक भाग अच्छी तरह से काम करता है।


-5

यह मेरे लिए ज़्यादा प्रधान है:

class CoolAdmin(admin.ModelAdmin):
    list_display = ('pk', 'submodel__field')

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.