سؤال

انا املك Person النموذج الذي له علاقة مفتاح خارجي Book, ، الذي يحتوي على عدد من الحقول ، لكنني أكثر قلقًا بشأنه author (تشارفيلد قياسي).

مع ما يقال ، في بلدي PersonAdmin النموذج ، أود عرضه book.author استخدام list_display:

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

لقد جربت كل الأساليب الواضحة للقيام بذلك ، لكن لا شيء يبدو أنه يعمل.

أي اقتراحات؟

هل كانت مفيدة؟

المحلول

كخيار آخر ، يمكنك البحث مثل:

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'

نصائح أخرى

على الرغم من كل الإجابات الرائعة أعلاه وبسبب كونني جديدًا على Django ، كنت لا أزال عالقًا. إليكم توضيحي من منظور مبتدئ للغاية.

النماذج

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 (الطريقة الصحيحة) - هذه هي الطريقة التي تشير بها إلى اسم مفتاح خارجي طريقة 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 هنا

مثل الباقي ، ذهبت مع Callables أيضا. لكن لديهم جانبًا سلبيًا واحد: افتراضيًا ، لا يمكنك طلبهم. لحسن الحظ ، هناك حل لذلك:

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

يرجى ملاحظة أن إضافة get_author ستؤدي الوظيفة إلى إبطاء list_display في المسؤول ، لأن إظهار كل شخص سيجعل استعلام SQL.

لتجنب ذلك ، تحتاج إلى تعديل get_queryset الطريقة في personadmin ، على سبيل المثال:

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

قبل: 73 استعلامات في 36.02 مللي ثانية (67 استفسارات مكررة في المشرف)

بعد: 6 استفسارات في 10.81ms

وفقًا للوثائق ، يمكنك فقط عرض __unicode__ تمثيل أجنبي:

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

يبدو من الغريب أنه لا يدعم 'book__author' تنسيق النمط الذي يتم استخدامه في كل مكان آخر في واجهة برمجة تطبيقات DB.

اتضح أن هناك تذكرة لهذه الميزة, ، والتي تم تمييزها كما لا إصلاح.

يمكنك إظهار ما تريد في عرض القائمة باستخدام قابلة للاتصال. انها تبدو مثل هذا:

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

class PersonAdmin(admin.ModelAdmin):
  list_display = [book_author,]

لقد نشرت للتو مقتطفًا يجعل Admin.ModelAdmin دعم "__" بناء جملة:

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

لذلك يمكنك أن تفعل:

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

هذا هو مجرد القيام بنفس الشيء الموضح في الإجابات الأخرى ، لكنه يعتني تلقائيًا (1) تعيين admin_order_field (2) تعيين Short_description و (3) تعديل QuerySet لتجنب ضرب قاعدة البيانات لكل صف.

This one's already accepted, but if there are any other dummies out there (like me) that didn't immediately get it from the presently accepted answer, here's a bit more detail.

The model class referenced by the ForeignKey needs to have a __unicode__ method within it, like here:

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

    def __unicode__(self):
        return self.name

That made the difference for me, and should apply to the above scenario. This works on Django 1.0.2.

إذا جربته في الخط ، فلن تنجح إلا إذا:

في خطتك:

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

إذا كان لديك الكثير من حقول سمات العلاقة لاستخدامها في list_display ولا تريد إنشاء وظيفة (وسماتها) لكل واحدة ، وسيتم تجاوز الحل الأوساخ ولكن البسيط ModelAdmin stace __getattr__ الطريقة ، إنشاء callables على الذبابة:

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 يجب تعريفها على أنها ModelAdmin سمات ، على سبيل المثال book__author_verbose_name = 'Author name' و category__is_new_boolean = True.

القابلة للاستدعاء admin_order_field يتم تعريف السمة تلقائيا.

لا تنس استخدام list_select_reled ميزة في الخاص بك ModelAdmin لجعل Django تجنب الاستفسارات الدهنية.

هناك حزمة سهلة الاستخدام متوفرة في PYPI تعالج بالضبط: إدارة Django. يمكنك أيضا انظر الرمز في جيثب.

باستخدام هذا ، ما تريد تحقيقه بسيط مثل:

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

يحتوي كلا الرابطين على تفاصيل كاملة للتثبيت والاستخدام ، لذا لن ألصقهما هنا في حالة تغييرها.

مثل ملاحظة جانبية ، إذا كنت تستخدم بالفعل شيء آخر غير model.Admin (على سبيل المثال كنت أستخدم SimpleHistoryAdmin بدلاً من ذلك) ، يمكنك القيام بذلك: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin).

عملت إجابة Alexrobbins بالنسبة لي ، إلا أن الخطين الأولين يجب أن يكونوا في النموذج (ربما تم افتراض ذلك؟) ، ويجب أن يشير إلى الذات:

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

ثم يعمل جزء المسؤول بشكل جيد.

أنا أفضل هذا:

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

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top