Django模板中如何统计EventSite关联所有Concert的艺术家总数量?
问题原因
你的原有代码无法返回正确结果的核心原因是:site.event_concert.all 返回的是多个Concert对象组成的查询集,而artists是单个Concert实例的属性,不能直接在查询集上调用该属性,因此无法拿到统计值。
推荐实现:视图层提前统计
Django的模板设计原则不推荐在模板中执行复杂计算,将统计逻辑放到视图层处理性能更好,还可以通过ORM聚合查询避免N+1查询问题。
统计所有艺术家总数
视图层查询代码如下:
from django.db.models import Count # 给每个EventSite对象 annotated 统计字段 event_sites = EventSite.objects.annotate( total_artists=Count('event_concert__artists', distinct=True) )
参数distinct=True用于去重:如果同一个艺术家关联了该场地的多场演唱会,不会被重复统计;如果需要按参演人次统计,移除该参数即可。
同时统计英国艺术家数量
通过条件聚合即可实现:
from django.db.models import Count, Q event_sites = EventSite.objects.annotate( total_artists=Count('event_concert__artists', distinct=True), british_artists=Count('event_concert__artists', filter=Q(event_concert__artists__is_british=True), distinct=True) )
模板中直接调用annotate生成的属性即可:
{% for site in event_sites %} {{ site.total_artists }}, <!-- 需要统计英国艺术家时替换为 {{ site.british_artists }} --> {% endfor %}
备选方案:自定义模板过滤器
如果无法修改视图层代码,可以通过自定义模板过滤器实现统计逻辑:
- 首先在你的app目录下新建
templatetags文件夹,添加__init__.py空文件和stats_filters.py文件,代码如下:
from django import template from django.db.models import Count, Q, Sum register = template.Library() @register.filter def get_total_artists(site): return site.event_concert.annotate( cnt=Count('artists', distinct=True) ).aggregate(total=Sum('cnt'))['total'] or 0 @register.filter def get_british_artists(site): return site.event_concert.annotate( cnt=Count('artists', filter=Q(artists__is_british=True), distinct=True) ).aggregate(total=Sum('cnt'))['total'] or 0
- 模板中加载过滤器后调用:
{% load stats_filters %} {% for site in event_sites %} {{ site|get_total_artists }}, <!-- 英国艺术家统计调用 {{ site|get_british_artists }} --> {% endfor %}
内容的提问来源于stack exchange,提问作者albertrw
相关产品推荐
相关产品推荐

