You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何统计关联Company的在线Ad数量?

问题描述

我开发了一个返回所有Company对象的视图,希望在companySearch.html模板中统计每个Company关联的、online字段为True的Ad数量。但当前模板会统计所有关联的Ad(包括online为False的),我期望实现类似{{ o.ad_set.count where o.ad.online == True }}的逻辑。

相关代码如下:

views.py

def companySearch(request):
    obj = Company.objects.all()
    
    paginator = Paginator(obj, PAGINATION_NUMBER)
    page_number = request.POST.get('page')
    page_obj = paginator.get_page(page_number)

    context = {'obj': page_obj}
    return render(request, 'core/companySearch.html', context)

models.py

class Company(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=64, blank=False, null=False, unique=True)    

class Ad(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=128, blank=False, null=False)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    online = models.BooleanField(default=False)

companySearch.html

{% for o in obj %}
    <div>{{ o.ad_set.count }} open position{{ o.ad_set.count|pluralize:',s' }}</div>
{% endfor %}

解决方案

方法1:模型中添加属性(简单易实现)

给Company模型新增一个属性,专门返回在线广告的数量:

class Company(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=64, blank=False, null=False, unique=True)    

    @property
    def online_ad_count(self):
        return self.ad_set.filter(online=True).count()

模板中直接调用该属性:

{% for o in obj %}
    <div>{{ o.online_ad_count }} open position{{ o.online_ad_count|pluralize:',s' }}</div>
{% endfor %}

⚠️ 注意:这种方式会为每个Company单独发起数据库查询,数据量大时可能影响性能。

方法2:视图用annotate预计算(性能最优)

在查询Company时,通过annotate提前统计好每个公司的在线广告数量,只需要一次数据库查询:

from django.db.models import Count, Q

def companySearch(request):
    obj = Company.objects.annotate(
        online_ad_count=Count('ad', filter=Q(ad__online=True))
    )
    
    paginator = Paginator(obj, PAGINATION_NUMBER)
    page_number = request.POST.get('page')
    page_obj = paginator.get_page(page_number)

    context = {'obj': page_obj}
    return render(request, 'core/companySearch.html', context)

模板中同样使用o.online_ad_count即可,和方法1的模板代码一致。

方法3:模板直接过滤(不推荐)

虽然Django模板支持直接过滤,但会引发N+1查询问题,性能较差,不建议使用:

{% for o in obj %}
    <div>{{ o.ad_set.filter(online=True).count }} open position{{ o.ad_set.filter(online=True).count|pluralize:',s' }}</div>
{% endfor %}

内容的提问来源于stack exchange,提问作者GCMeccariello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 23:58:28