如何向具有多对一关系的模型的 Django 管理员添加可排序的计数列?

Posted

技术标签:

【中文标题】如何向具有多对一关系的模型的 Django 管理员添加可排序的计数列?【英文标题】:How to add a sortable count column to the Django admin of a model with a many-to-one relation? 【发布时间】:2011-03-30 08:06:54 【问题描述】:

假设我有一个 Book 模型,其中包含一个 Publisher 模型的外键。

如何在 Django 管理中显示每个出版商出版的书籍数量的列,以我可以使用内置排序的方式?

【问题讨论】:

books.agiliq.com/projects/django-admin-cookbook/en/latest/… 应该是查看的正确位置 【参考方案1】:

我遇到了同样的问题(我无法更改模型的管理器来添加慢速注释或连接)。这里的两个答案的组合有效。 @Andre 非常接近,Django Admin 支持仅为管理员修改查询集,因此在此处应用相同的逻辑,然后使用 admin_order_field 属性。当然,您仍然需要将新的管理字段添加到 list_display。

from django.db.models import Count

class EventAdmin(admin.ModelAdmin)
    list_display = (..., 'show_artist_count')

    def queryset(self, request):
    # def get_queryset(self, request):    for Django 1.6+
        qs = super(EventAdmin, self).queryset(request)
        return qs.annotate(artist_count=Count('artists'))

    def show_artist_count(self, inst):
        return inst.artist_count
    show_artist_count.admin_order_field = 'artist_count'

【讨论】:

有没有办法将此设置为默认订购方式? ordering = ('artist_count') 例如。对我来说失败,字段不存在。 别忘了添加这一行:from django.db.models import Count Since Django 1.6 ModelAdmin 方法被命名为 get_queryset 而不是 queryset 它适用于初始加载,但如果我在对象上搜索,匹配的结果会给出错误的计数。不知道它是如何得出一些奇怪的数字的。 queryset 变为 get_queryset 也可在 Django 1.6+ 上调用 super()qs = super(EventAdmin, self).get_queryset(request)【参考方案2】:

试试这个:

创建一个新的Manager(和aggregate,并在图书关系字段中计数):

class PublisherManager(models.Manager):
    def get_query_set(self):
        return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))

pubcount上排序:

class Publisher(models.Model):
    ......
    objects = PublisherManager()

    class Meta:
        ordering = ('pubcount',)

【讨论】:

噢——这是一个非常巧妙的技巧,但请记住,它会为您使用扩展对象管理器查找的所有内容添加注释。如果这是一个问题,您总是可以创建第二个没有聚合的标准管理器,并将其附加为“standard_objects”。但这确实增加了复杂性,obv @stevejalim,没错。如果计数器不必是“实时的”,您还可以在出版商上有一个 book_count 字段,并在保存一本书时用信号更新它..... 当我尝试这个时,我收到一个错误:“ordering”指的是“pubcount”,一个不存在的字段。 另外,您如何将其集成为管理中的可排序列? @GJ。你解决了这个问题吗?我现在也有同样的问题。【参考方案3】:

你确实应该从添加开始:

class PublisherManager(models.Manager):
    def get_query_set(self):
        return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))

但将其添加为可排序字段的正确方法是:

class Publisher(models.Model):
    ......
    objects = PublisherManager()

    def count(self):
        return self.pubcount
    count.admin_order_field = 'pubcount'

然后你可以在 admin.py 中的 model admin 的 list_display 属性中添加 'count'

【讨论】:

【参考方案4】:

Lincoln B 的回答对我来说是正确的。

起初我只想评论他的解决方案,但实际上我发现自己解决了一个稍微不同的问题。我有一个管理类,我想根据我的需要“定制”它——即django-taggit admin。在我的一个应用程序的admin.py 中,我添加了:

# sort tags by name in admin (count items also possible)
from taggit.admin import TagAdmin
TagAdmin.ordering = ["name"]
#   make sortable on item_count:
# 1. function for lookup
def item_count(obj):
    """This takes the item_count from object: didn't work as model field."""
    return obj.item_count # not needed: obj.taggit_taggeditem_items.count()
# 2. property in function - admin field name
item_count.admin_order_field = 'item_count'
# 3. queryset override, with count annotation
from django.db.models import Count
TagAdmin.queryset = lambda self, request: super(TagAdmin, self).queryset(request).annotate(item_count=Count('taggit_taggeditem_items'))
# 4. add to list display
TagAdmin.list_display = ["name", item_count]

对我来说有趣的观察是,我不能只注释queryset,并将"item_count" 添加到list_display - 因为TagAdmin 中没有item_count 方法,也没有方法或字段Tag 模型类(仅在 queryset 中)。

【讨论】:

【参考方案5】:

试试这样的:

class PublisherAdminWithCount(Admin):

    def book_count(self, obj):
        return obj.book_set.count()

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)

【讨论】:

很遗憾,该列无法排序。

以上是关于如何向具有多对一关系的模型的 Django 管理员添加可排序的计数列?的主要内容,如果未能解决你的问题,请参考以下文章

我需要使用具有多对一关系的@Access=FIELD 注释吗?

连接两个共享多对一关系的 SQL 表

将多个文件发布到数据库 - 多对一关系的空值

一对多和多对一关系的区别

Doctrine 2 - 多对一关系的外键不允许空值

双向多对一关系的增删改查