Django ORM如何统计模型对象间非去重多对多关联总数
问题描述
假设定义了如下Django模型:
class Tag(Model): name = CharField() class Book(Model): title = CharField() tags = ManyToManyField(Tag)
现有3本图书,每本关联3个标签,不同图书允许关联重复标签,不影响统计逻辑,示例数据如下:
Book 1 (Tags = "tag1", "tag2", "tag3") Book 2 (Tags = "tag1", "tag4", "tag5") Book 3 (Tags = "tag4", "tag5", "tag6")
需求是编写Django ORM查询语句,统计所有非去重的标签关联总次数,预期结果为9。
实现方法
Django的多对多字段会自动生成一张中间关联表,表中每一行记录就对应一次「图书-标签」的绑定关系,哪怕多个图书绑定同一个标签,也会生成独立的记录,不存在去重逻辑,直接统计这张表的总记录数就能得到想要的结果,写法最简单性能也最高:
total_relation_count = Book.tags.through.objects.count()
执行上述语句返回的结果就是9,完全匹配需求。
避坑说明
- 不要用
Tag.objects.count():这个语句统计的是去重后的标签总数量,按照示例数据返回结果是6,不符合要求。 - 不推荐用聚合嵌套写法:比如
Book.objects.annotate(t_num=Count('tags')).aggregate(total=Sum('t_num'))虽然计算结果也对,但会先按图书分组统计每本书的标签数,再做求和,数据量大的时候性能远差于直接统计中间表。 - 调试时可以直接遍历中间表记录核对关联关系:
for rel in Book.tags.through.objects.all(): print(f"关联关系:图书ID {rel.book_id} <-> 标签ID {rel.tag_id}")
内容的提问来源于stack exchange,提问作者Salvatore Iovene
相关产品推荐
相关产品推荐

