Django使用ORM查询Product时产生大量重复查询问题求助
Django ORM重复查询问题修复方案
问题根源
你遇到的114条重复查询是典型的N+1查询问题,同时原有评分计算逻辑存在三处冗余:
get_rating属性每次被调用都会触发一次独立的数据库查询,当页面渲染多个商品时,每个商品都会单独发起一次评分查询- 原有
select_related('r_product')完全无用:你是从当前Product实例反向查询关联的评价,r_product本身就指向当前Product,不需要额外连表查询 - 直接遍历所有评价记录计算总分,会拉取不必要的全量评价字段,浪费数据库和内存资源
优化步骤
第一步:优化get_rating属性逻辑
使用Django ORM的聚合函数直接在数据库层面计算评分总和,不需要拉取全量评价记录,查询效率提升明显。
修改Product模型的get_rating属性:
# 模型文件顶部先导入聚合函数 from django.db.models import Sum @property def get_rating(self): # 直接用Sum聚合计算,数据库层面完成计算,返回的就是总分,无评价时默认返回0 return self.reviews.aggregate(total=Sum('stars'))['total'] or 0
第二步:批量查询商品时彻底消灭N+1查询
如果你是在商品列表页等场景查询多个商品,有两种方案可选,按需使用:
方案1:提前预加载关联评价(适合需要用到其他评价字段的场景)
查询商品时用prefetch_related一次性拉取所有关联评价,后续调用get_rating不会再发起新查询:
# 示例查询语句 product_list = Product.objects.filter(status="Active").prefetch_related("reviews")
方案2:查询时直接注解评分(性能最优,仅需要总分时推荐)
直接在查询商品的语句中用annotate把评分总和算好,一次查询就能拿到所有商品的评分,不需要额外调用get_rating:
from django.db.models import Sum product_list = Product.objects.filter(status="Active").annotate( total_rating=Sum("reviews__stars") ) # 后续直接取product.total_rating就能拿到总分,不需要再调用get_rating属性
改完后重复查询问题会完全消失,数据库查询次数会降到1-2次。
内容的提问来源于stack exchange,提问作者Kuldeep
相关产品推荐
相关产品推荐

