如何在django admin中显示list_filter和相关对象的数量?

时间:2016-11-14 17:05:06

标签: django-admin django-modeladmin

如何在django admin的list_filter中显示每个过滤器后的相关对象的数量?

class Application(TimeStampModel):

    name = models.CharField(verbose_name='CI Name', max_length=100, unique=True)
    description = models.TextField(blank=True, help_text="Business application")

class Server(TimeStampModel):
    name = models.CharField(max_length=100, verbose_name='Server Name', unique=True)
    company = models.CharField(max_length=3, choices=constants.COMPANIES.items())
    online = models.BooleanField(default=True, blank=True, verbose_name='OnLine')
    application_members = models.ManyToManyField('Application',through='Rolemembership',
            through_fields = ('server', 'application'),
            )


class Rolemembership(TimeStampModel):

    server = models.ForeignKey(Server, on_delete = models.CASCADE)
    application = models.ForeignKey(Application, on_delete = models.CASCADE)
    name = models.CharField(verbose_name='Server Role', max_length=50, choices=constants.SERVER_ROLE.items())
    roleversion = models.CharField(max_length=100, verbose_name='Version', blank=True)

Admin.py

@admin.register(Server)
class ServerAdmin(admin.ModelAdmin):

    save_on_top = True
    list_per_page = 30
    list_max_show_all = 500
    inlines = [ServerInLine]

    list_filter = (
        'region',
        'rolemembership__name',
        'online',
        'company',
        'location',
        'updated_on',
    )

即在列表过滤器中的每个过滤器之后,我想显示相关对象的数量。

现在它只显示过滤器列表 即位置过滤列表

  • 多伦多
  • NY
  • 芝加哥

我希望过滤器显示如下计数:

  • 多伦多(5)
  • NY(3)
  • 芝加哥(2)

如果过滤器有0个相关对象,请不要显示过滤器。

2 个答案:

答案 0 :(得分:4)

通过结合两个想法,可以使用自定义列表过滤器。

一:lookups方法允许您控制查询字符串中使用的值以及显示为过滤器文本的文本。

二:您可以在构建过滤器列表时检查数据集。 https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter的文档显示了开始十年列表过滤器的示例(始终显示«80s»和«90s»)和动态过滤器(如果有匹配的记录则显示“80s”,“90s”相同)。< / p>

  

同样为方便起见,将ModelAdmin对象传递给查找   方法,例如,如果您希望将查找基于可用的   数据

这是我用语言过滤数据的过滤器:

class BaseLanguageFilter(admin.SimpleListFilter):
    title = _('language')
    parameter_name = 'lang'

    def lookups(self, request, model_admin):
        # Inspect the existing data to return e.g. ('fr', 'français (11)')
        # Note: the values and count are computed from the full data set,
        # ignoring currently applied filters.
        qs = model_admin.get_queryset(request)
        for lang, name in settings.LANGUAGES:
            count = qs.filter(language=lang).count()
            if count:
                yield (lang, f'{name} ({count})')

    def queryset(self, request, queryset):
        # Apply the filter selected, if any
        lang = self.value()
        if lang:
            return queryset.filter(language=lang)

您可以从中开始并根据settings.LANGUAGES将部分替换为带有查询集聚合+ values_list的部分来为您的城市进行调整,这将返回城市的不同值和计数。

答案 1 :(得分:0)

Éric的代码为我提供了80%的所需资源。为了解决他在代码中留下的评论(关于忽略当前应用的过滤器),我最终在用例中使用了以下内容:

from django.db.models import Count

class CountAnnotatedFeedFilter(admin.SimpleListFilter):
    title = 'feed'
    parameter_name = 'feed'

    def lookups(self, request, model_admin):
        qs = model_admin.get_queryset(request).filter(**request.GET.dict())
        for pk, name, count in qs.values_list('feed__feed_id', 'feed__feed_name').annotate(total=Count('feed')).order_by('-total'):
            if count:
                yield pk, f'{name} ({count})'

    def queryset(self, request, queryset):
        feed_id = self.value()
        if feed_id:
            return queryset.filter(feed_id=feed_id)

然后,在管理员模型中:

class FeedEntryAdmin(admin.ModelAdmin):
    list_filter = (CountAnnotatedFeedFilter,)

注意:正如Éric也提到的那样,这可能会极大地影响管理面板的速度,因为它可能必须执行昂贵的查询。