Django无外键关联时,如何跨表注解统计影片制片方总浏览量?
问题描述
现有三个Django模型/数据表:
class Stats: obj_type = models.TextField(blank=True, db_index=True) obj_id = models.PositiveIntegerField(blank=True, null=True, db_index=True) views_count = models.IntegerField(blank=True, null=True, default=0) class Movie: title = models.TextField(blank=True) producer = models.TextField(blank=True) class Cartoon: title = models.TextField(blank=True) producer = models.TextField(blank=True)
Stats表约有150万条数据,其中obj_type字段存储'Movie'或'Cartoon'字符串,对应关联Movie或Cartoon表的记录(无外键关联)。
需要获取Movie表中所有制片方的列表,以及每个制片方对应的总浏览量(统计依据为Stats表中对应Movie的views_count之和),示例输出:
Walt Disney: 17055 # 所有制片方为'Walt Disney'的Movie的总浏览量 Netflix: 15046 etc.
希望实现类似“浏览量字段在Movie表中”时的简洁写法:
views = Movie.objects.values('producer').annotate(count=Sum('views_count'))
最优实现方案
直接通过Django ORM构造数据库层面的关联查询,避免在Python内存中处理大量数据,保证效率:
from django.db.models import Sum result = Movie.objects.filter( id__in=Stats.objects.filter(obj_type='Movie').values('obj_id') ).values('producer').annotate(total_views=Sum('stats__views_count')).order_by('-total_views')
原理说明
- 先筛选Stats表中
obj_type='Movie'的记录,获取对应的obj_id(即Movie的id) - 关联Movie表,按
producer分组,统计每组关联的Stats记录中views_count的总和 - 利用现有索引:Stats的
obj_type和obj_id已加索引,Movie的id是主键索引,数据库会高效执行关联查询
输出处理
如果需要直接输出示例格式的结果,可以遍历查询集:
for item in result: print(f"{item['producer']}: {item['total_views']}")
性能优化提示
- 若Movie表的
producer字段查询频繁,可添加db_index=True,进一步提升分组统计效率 - 绝对避免Python循环逐条关联查询(比如先查所有Movie,再逐个查对应Stats求和),这种方式会产生百万级查询,性能极差
内容的提问来源于stack exchange,提问作者Edmond
相关产品推荐
相关产品推荐

