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

发布于 2024-09-14 04:18:16 字数 97 浏览 3 评论 0原文

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

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

Suppose I have a Book model containing a foreign key to a Publisher model.

How can I display in the Django admin a column with the number of books published by each publisher, in a way that I can use the built-in sorting?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我们的影子 2024-09-21 04:18:16

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

姜戈1.6:

from django.db.models import Count

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

    def queryset(self, request):
        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'

姜戈 > 1.6:

from django.db.models import Count

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

    def get_queryset(self, request):
        qs = super().get_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"

I had the same issue (I cannot change my model's manager to add slow annotations or joins). A combination of two of the answers here works. @Andre is really close, the Django Admin supports modifying the queryset for just the admin, so apply the same logic here and then user the admin_order_field attribute. You still need to add the new admin field to list_display, of course.

Django < 1.6:

from django.db.models import Count

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

    def queryset(self, request):
        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'

Django > 1.6:

from django.db.models import Count

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

    def get_queryset(self, request):
        qs = super().get_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"
溺ぐ爱和你が 2024-09-21 04:18:16

试试这个:

创建一个新的 Manager (和 聚合,其中包含图书关系字段的计数):

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',)

Try this:

make a new Manager (and aggregate with count on the book relation field):

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

sort it on pubcount:

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

    class Meta:
        ordering = ('pubcount',)
前事休说 2024-09-21 04:18:16

您确实应该从添加开始:

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'

然后您可以将“count”添加到 admin.py 中模型管理的 list_display 属性中

You should indeed start off with adding:

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

But the correct way to add it as a sortable field is:

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

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

And then you can just add 'count' to the list_display attribute of model admin in admin.py

醉梦枕江山 2024-09-21 04:18:16

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

起初我只想评论他的解决方案,但实际上我发现自己解决了一个略有不同的问题。我有一个管理类,我想根据我的需要“定制”它 - 即 django-taggit 管理类。在我的一个应用程序的 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 中也没有方法或字段code> 模型类(仅在 queryset 中)。

Lincoln B's answer was the right way for me.

At first I wanted to just comment on his solution, but I actually found myself solving a slightly different problem. I had an admin class, which I wanted to "customize" to my needs - namely the django-taggit admin. In one of my application's admin.py, I added:

# 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]

The interesting observation for me was, that I could not just annotate the queryset, and add "item_count" to list_display - because there was no item_count method in TagAdmin, nor a method or field in the Tag model class (only in the queryset).

情定在深秋 2024-09-21 04:18:16

尝试这样的事情:

class PublisherAdminWithCount(Admin):

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

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)

Try something like this:

class PublisherAdminWithCount(Admin):

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

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文