我有一个Person模型,它与Book有外键关系,Book有许多字段,但我最关心的是author(一个标准CharField)。

话虽如此,在我的PersonAdmin模型中,我想显示book。作者使用list_display:

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

我已经尝试了所有显而易见的方法,但似乎都不起作用。

有什么建议吗?


当前回答

在PyPI中有一个非常容易使用的包可以处理这个问题:django-related-admin。你也可以在GitHub中看到代码。

使用它,你想要达到的效果很简单:

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

这两个链接都包含了安装和使用的全部细节,所以我不会把它们粘贴在这里,以防它们发生变化。

顺便说一句,如果你已经在使用模型以外的东西。Admin(例如,我使用的是SimpleHistoryAdmin代替),你可以这样做:类MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)。

其他回答

对于Django >= 3.2

在Django 3.2或更高版本中,正确的方法是使用显示装饰器

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

    @admin.display(description='Author Name', ordering='author__name')
    def get_author_name(self, obj):
        return obj.author.name

我可能会迟到,但这是另一种方法。你可以简单地在你的模型中定义一个方法,并通过list_display访问它,如下所示:

models.py

class Person(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)

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

admin.py

class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_book_author',)

但是这种方法和上面提到的其他方法会在列表视图页面的每一行中增加两个额外的查询。为了优化这一点,我们可以覆盖get_queryset来注释所需的字段,然后在ModelAdmin方法中使用注释的字段

admin.py

from django.db.models.expressions import F

@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_author',)
    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(
            _author = F('book__author')
        )
        return queryset

    @admin.display(ordering='_author', description='Author')
    def get_author(self, obj):
        return obj._author

你可以使用可调用对象在列表显示中显示你想要的任何东西。它看起来是这样的:


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

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

这个答案已经被接受了,但如果还有其他傻瓜(比如我)没有立即从目前接受的答案中得到它,这里有更多的细节。

ForeignKey引用的模型类需要有一个__unicode__方法,如下所示:

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

    def __unicode__(self):
        return self.name

这对我来说很重要,也适用于上述情况。这适用于Django 1.0.2。

我刚刚发布了一个片段,使管理。ModelAdmin支持'__'语法:

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

所以你可以这样做:

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

这基本上只是做与其他回答中描述的相同的事情,但它自动负责(1)设置admin_order_field(2)设置short_description和(3)修改queryset以避免对每一行进行数据库命中。