【问题标题】:How to display list_filter with count of related objects in django admin?如何在 django admin 中显示 list_filter 和相关对象的数量?
【发布时间】:2017-03-28 09:45:38
【问题描述】:

如何在 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',
    )

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

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

  • 多伦多
  • 纽约
  • 芝加哥

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

  • 多伦多(5)
  • 纽约(3)
  • 芝加哥(2)

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

【问题讨论】:

  • 到目前为止你有任何代码吗?
  • 见上面的例子。
  • 位置是对象吗?还是字符串输入?还是选择?
  • 地点是选择。
  • 这可能吗。关于如何解决这个问题的任何想法?

标签: django-admin django-modeladmin


【解决方案1】:

É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 还提到的,这会严重影响管理面板的速度,因为它可能必须执行昂贵的查询。

【讨论】:

    【解决方案2】:

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

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

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

    同样为了方便,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 的部分来适应您的城市,这将返回城市的不同值和计数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-02
      • 2020-08-24
      • 2023-03-03
      • 2021-02-07
      • 1970-01-01
      • 2013-05-15
      • 2012-10-18
      • 2013-10-20
      相关资源
      最近更新 更多