如何用Django ORM的annotate与Subquery获取各店铺最低价商品
用Django的annotate和Subquery实现每个店铺筛选后商品的最低成本商品查询
没问题,我来帮你搞定这个需求!要实现从每个店铺的筛选后商品集合里,拿到total_cost最低的那件商品,结合annotate和Subquery可以分两步来实现,逻辑清晰且性能友好。
步骤1:定义你的基础筛选商品集合
首先先确认你已经有了筛选后的商品集合,比如假设你是按某个分类、时间范围筛选的,先把这个集合定义好:
from django.db.models import Subquery, OuterRef, Min # 这里替换成你的实际筛选条件,比如按商品类型、上架时间等 filtered_goods = Goods.objects.filter( # 示例条件:比如商品属于某个分类 # category='daily_necessities' )
步骤2:构建子查询获取每个店铺的最低成本值
先通过子查询计算出每个店铺在筛选后的商品中,total_cost的最小值:
# 子查询:针对每个店铺,计算其筛选后商品的最小total_cost min_cost_subquery = filtered_goods.filter( store=OuterRef('pk') # 关联外层查询的Store主键 ).values('store').annotate( min_cost=Min('total_cost') ).values('min_cost')
步骤3:匹配到对应最低成本的商品
接下来再构建一个子查询,找到每个店铺中total_cost等于上述最小值的商品(如果有多个相同最小值的商品,我们用[:1]确保每个店铺只返回一条,你可以根据需求调整排序规则):
# 子查询:获取每个店铺中符合筛选条件且成本最低的商品ID lowest_cost_good_subquery = filtered_goods.filter( store=OuterRef('pk'), total_cost=Subquery(min_cost_subquery) ).order_by('id')[:1] # 按id排序取第一个,避免多条重复最小值的情况
步骤4:获取最终结果
最后通过商品ID筛选,得到每个店铺对应的最低成本商品集合:
# 最终查询结果:每个店铺筛选后商品中成本最低的那件 result = Goods.objects.filter( pk__in=Subquery(lowest_cost_good_subquery) )
额外技巧:直接从Store模型关联查询
如果你需要同时获取店铺信息和对应的最低成本商品,可以直接在Store查询中annotate:
stores_with_lowest_good = Store.objects.annotate( lowest_good_id=Subquery(lowest_cost_good_subquery) ).filter(lowest_good_id__isnull=False) # 若要直接拿到Goods对象,可通过id筛选 goods_result = Goods.objects.filter( pk__in=stores_with_lowest_good.values('lowest_good_id') )
注意事项
- 如果你的筛选条件比较复杂,确保
filtered_goods已经正确包含了所有需要考虑的商品。 - 当多个商品的
total_cost完全相同时,order_by('id')[:1]会取id最小的那条,你可以改成order_by('-create_time')[:1]来取最新上架的,根据业务需求调整即可。 OuterRef的作用是引用外层查询的字段,这里外层如果是Store查询就用OuterRef('pk'),如果是Goods查询要对应调整引用的字段。
内容的提问来源于stack exchange,提问作者Ernst
相关产品推荐
相关产品推荐

