如何使用Django ORM实现嵌套Group By 统计各出版社对应图书出版数量
解决方法
问题原因
你当前的代码query_set.values('publisher', 'title').annotate(count=Count('title'))是按照publisher和title两个字段联合分组,最终得到的是每条数据对应一个「出版社+书名」的独立统计项,没有做按出版社的二次聚合,所以无法直接输出嵌套结构。
推荐实现方案(全版本兼容)
先通过ORM拿到基础统计数据,再用Python做二次组装,逻辑清晰且兼容所有Django版本:
from django.db.models import Count # 获取出版社+书名维度的统计数据 stat_data = query_set.values("publisher", "title").annotate(count=Count("title")).order_by("publisher") # 组装为目标嵌套格式 res = [] current_publisher = None pub_info = None for item in stat_data: pub = item["publisher"] title = item["title"] cnt = item["count"] # 遇到新出版社则创建新条目 if pub != current_publisher: if pub_info: res.append(pub_info) pub_info = {"publisher": pub, "titles": {}} current_publisher = pub pub_info["titles"][title] = cnt # 补充最后一个出版社的条目 if pub_info: res.append(pub_info)
运行后得到的res就完全符合你需要的格式。
高版本Django简化方案(Django >= 4.0)
如果使用Django 4.0及以上版本,可以借助JSONBAgg和JSONObject在数据库层面完成部分聚合,减少Python层的遍历逻辑:
from django.db.models import Count, F, JSONBAgg from django.db.models.functions import JSONObject res = list( query_set.values("publisher", "title") .annotate(count=Count("title")) .values("publisher") .annotate( titles=JSONBAgg( JSONObject(key=F("title"), value=F("count")) ) ) .values("publisher", "titles") ) # 仅需一步转换把数组转成字典 for item in res: item["titles"] = {i["key"]: i["value"] for i in item["titles"]}
内容的提问来源于stack exchange,提问作者Ibrahim Noor
相关产品推荐
相关产品推荐

