如何使用Django ORM实现内连接查询获取各菜系最贵菜品的完整信息
解决Django ORM查询每个菜系最高价菜品完整信息的问题
你提到的Dishes.objects.values('cuisine').annotate(max_price=Max("price"))确实只能拿到分组后的菜系和对应最高价格——因为values()会限制返回的字段,加上annotate()后是做分组聚合,没法直接拿到菜品的完整信息。下面给你两种可行的方案,其中第一种用子查询的方式更高效,符合你想要的内连接逻辑:
方案一:使用子查询(推荐)
这种方式通过子查询先计算每个菜系的最高价格,再关联原表筛选出对应价格的菜品,只需要一次数据库查询:
from django.db.models import Max, Subquery, OuterRef # 定义子查询:针对每个外层的菜系,计算该菜系的最高价格 max_price_subquery = Dishes.objects.filter( cuisine=OuterRef('cuisine') # 引用外层查询的cuisine字段 ).values('cuisine').annotate( max_price=Max('price') ).values('max_price') # 只返回max_price字段作为子查询结果 # 查询符合条件的完整菜品信息 top_dishes = Dishes.objects.filter( price=Subquery(max_price_subquery) # 筛选价格等于对应菜系最高价格的菜品 ) # 遍历输出示例 for dish in top_dishes: print(f"菜系: {dict(Dishes.cuisine_list)[dish.cuisine]}, 菜名: {dish.name}, 价格: {dish.price}, 食材: {dish.material}")
原理说明:
OuterRef用来引用外层查询中的cuisine字段,子查询会动态计算当前外层菜系的最高价格- 外层的
filter(price=Subquery(...))相当于做了一次内连接,只保留价格等于对应菜系最高价格的菜品 - 如果同一个菜系有多个菜品价格同为最高,这个查询会返回所有这些菜品;如果只需要每个菜系返回一条,可以加上
.order_by('cuisine', '-price').distinct('cuisine')(注意:MySQL中使用distinct('cuisine')需要配合order_by指定该字段)
方案二:先获取最高价格集合再关联筛选
这种方式分两步,先拿到每个菜系的最高价格,再通过多条件筛选匹配原表:
from django.db.models import Max, Q # 第一步:获取每个菜系对应的最高价格字典 cuisine_max_map = { item['cuisine']: item['max_price'] for item in Dishes.objects.values('cuisine').annotate(max_price=Max('price')) } # 第二步:筛选出符合菜系和对应最高价格的菜品 top_dishes = Dishes.objects.filter( # 使用Q对象组合多个条件,确保每个菜品的菜系和价格匹配对应的最高价格 Q(*[Q(cuisine=c, price=p) for c, p in cuisine_max_map.items()]) )
注意点:
- 这种方式会发起两次数据库查询,数据量较大时效率不如方案一
- 同样会返回所有价格等于菜系最高值的菜品
为什么原来的查询无法拿到完整信息?
你原来的查询使用了values('cuisine'),这会让Django ORM只返回cuisine字段和聚合后的max_price,相当于SQL中的GROUP BY cuisine,分组后只能拿到分组字段和聚合结果,无法获取分组内的其他详情字段。
内容的提问来源于stack exchange,提问作者frank_xu
相关产品推荐
相关产品推荐

