Django ModelAdmin 中的“list_display”可以显示ForeignKey字段的属性吗?

2025-02-12 10:03:00
admin
原创
51
摘要:问题描述:我有一个Person与有外键关系的模型Book,它有多个字段,但我最关心的是author(标准 CharField)。话虽如此,在我的PersonAdmin模型中,我想book.author使用以下内容进行显示list_display:class PersonAdmin(admin.ModelAdm...

问题描述:

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

话虽如此,在我的PersonAdmin模型中,我想book.author使用以下内容进行显示list_display

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

我尝试了所有显而易见的方法,但似乎没有任何效果。

有什么建议吗?


解决方案 1:

作为另一种选择,您可以进行如下查找:

#models.py
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 3.2 或更高版本,请参考此答案

解决方案 2:

尽管上面所有答案都很棒,但由于我是 Django 新手,我仍然陷入困境。以下是我从新手的角度给出的解释。

模型.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(正确方法) -这是以 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:

请注意,添加该get_author功能会减慢管理员中的 list_display 速度,因为显示每个人都会进行 SQL 查询。

为了避免这种情况,您需要修改get_querysetPersonAdmin 中的方法,例如:

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

之前:36.02 毫秒内执行了 73 个查询(管理中执行了 67 个重复查询)

之后:10.81 毫秒内执行了 6 个查询

解决方案 4:

和其他人一样,我也使用了可调用函数。但是它们有一个缺点:默认情况下,您无法对它们进行订购。幸运的是,有一个解决方案:

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'

解决方案 5:

对于 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

解决方案 6:

根据文档,您只能显示__unicode__ForeignKey 的表示:

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

似乎奇怪的是它不支持'book__author'DB API 中其他地方使用的样式格式。

事实证明,此功能有一张票,标记为“无法修复”。

解决方案 7:

我刚刚发布了一个使 admin.ModelAdmin 支持“__”语法的代码片段:

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

因此你可以这样做:

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

这基本上只是做其他答案中描述的同样的事情,但它会自动处理(1)设置 admin_order_field (2)设置 short_description 和(3)修改查询集以避免每行都命中数据库。

解决方案 8:

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

使用这个,你想要实现的目标很简单:

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

两个链接都包含安装和使用的完整详细信息,因此我不会在这里粘贴它们,以防它们发生变化。

顺便提一下,如果您已经在使用其他东西model.Admin(例如我正在使用SimpleHistoryAdmin),您可以这样做:class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)

解决方案 9:

您可以使用可调用函数在列表显示中显示任何您想要的内容。它看起来像这样:


def book_author(对象):
  返回 object.book.author

类 PersonAdmin(admin.ModelAdmin):
  list_display = [书籍作者,]

解决方案 10:

我可能迟到了,但这是另一种方法。您只需在模型中定义一个方法并通过list_display以下方式访问它:

模型.py

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

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

管理工具

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

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

管理工具

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

解决方案 11:

这个已经被接受了,但是如果还有其他傻瓜(像我一样)没有立即从目前接受的答案中得到它,这里有更详细的信息。

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

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

    def __unicode__(self):
        return self.name

这对我来说有所不同,并且应该适用于上述情况。这适用于 Django 1.0.2。

解决方案 12:

如果你在 Inline 中尝试,你将不会成功,除非:

在您的内联中:

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

解决方案 13:

如果您有很多关系属性字段需要使用,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必须定义为ModelAdmin属性,例如book__author_verbose_name = 'Author name'category__is_new_boolean = True

可调用admin_order_field属性是自动定义的。

不要忘记使用list_select_related属性ModelAdmin来让 Django 避免额外的查询。

解决方案 14:

Django >= 5.1

从 Django 5.1 开始,使用 __ 引用模式也可以更轻松地实现这一点!

https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display

这个特定问题的解决方案如下:

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

解决方案 15:

AlexRobbins 的答案对我有用,只是前两行需要在模型中(也许这是假设的?),并且应该引用自身:

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

然后管理部分就可以正常运行了。

解决方案 16:

我更喜欢这个:

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

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用