如何使用Django ORM为Cafe QuerySet添加统计注解?
Django ORM实现咖啡馆统计数据查询
完全可以通过Django ORM实现这个需求,利用annotate结合聚合函数与条件表达式就能在数据库层面完成统计计算,无需在Python代码中二次处理数据。
实现代码
首先导入所需的ORM工具:
from django.db.models import Count, Case, When, FloatField, F
然后构建QuerySet:
# 获取包含统计字段的咖啡馆查询集 cafes_with_stats = Cafe.objects.annotate( # 统计每个咖啡馆的食品总数 total_foods=Count('foods'), # 统计未售食品总数,仅计数状态为NOT_SOLD_OUT的食品 unsold_foods=Count( Case( When(foods__status=Food.SoldStatus.NOT_SOLD_OUT, then='foods__id') ) ), # 计算未售食品占比,处理无食品时的除数为0问题 unsold_ratio=Case( When(total_foods=0, then=0.0), default=F('unsold_foods') / F('total_foods'), output_field=FloatField() ) )
使用说明
- 如果需要字典格式的结果,可在末尾添加
.values('name', 'total_foods', 'unsold_foods', 'unsold_ratio'),返回的每条数据就是包含指定字段的字典。 - 如果需要保留Cafe模型对象,直接遍历
cafes_with_stats即可通过对象属性访问统计字段:
for cafe in cafes_with_stats: print(f"咖啡馆:{cafe.name}") print(f"食品总数:{cafe.total_foods}") print(f"未售食品数:{cafe.unsold_foods}") print(f"未售占比:{cafe.unsold_ratio:.2%}\n")
关键逻辑说明
Count('foods'):通过外键的related_name直接统计关联的Food数量。Case+When:实现条件过滤,仅对状态为NOT_SOLD_OUT的食品进行计数。F表达式:让数据库层面完成除法计算,避免Python与数据库之间的数据传输,提升效率。- 除数为0处理:通过
Case判断如果食品总数为0,直接返回0.0,避免出现计算错误。
内容的提问来源于stack exchange,提问作者Jasur
相关产品推荐
相关产品推荐

