如何用Django Model ORM实现按钠含量降序、去重取Top3产品?
解决Django ORM查询去重并按钠含量排序的问题
你的需求是从Product表中获取每个唯一product的最高钠含量记录,按sodium降序排列后取前3条。当前代码仅做了排序和截取,未处理product去重,导致出现重复结果。
问题分析
当前代码Product.objects.all().order_by('-sodium')[:5]只是按钠含量降序取前5条,但同一product(比如chips)有多条高钠记录时会被全部取出,不符合「每个product仅保留一条最高钠含量记录」的需求。
解决方案
根据数据库类型不同,提供两种可行方案:
方案1:PostgreSQL专属(支持指定字段去重)
利用Subquery和OuterRef定位每个product的最高钠含量记录,再通过distinct去重:
from django.db.models import Subquery, OuterRef, Max # 子查询:获取每个product对应的最大sodium值 max_sodium_subquery = Product.objects.filter( product=OuterRef('product') ).values('product').annotate(max_sodium=Max('sodium')).values('max_sodium') # 筛选匹配最大sodium的记录,按sodium降序后按product去重,取前3 top_products = Product.objects.filter( sodium=Subquery(max_sodium_subquery) ).order_by('-sodium', 'product').distinct('product')[:3]
方案2:全数据库兼容(含MySQL)
先通过分组聚合拿到每个product的最高钠含量,再筛选原表记录并手动去重:
from django.db.models import Max # 第一步:获取每个product的最大sodium值 product_max_sodium = Product.objects.values('product').annotate(max_sodium=Max('sodium')) product_max_map = {item['product']: item['max_sodium'] for item in product_max_sodium} # 第二步:筛选符合条件的记录并排序 queryset = Product.objects.filter( product__in=product_max_map.keys(), sodium__in=product_max_map.values() ).order_by('-sodium') # 第三步:手动去重,保留每个product的第一条记录 unique_products = [] seen_products = set() for item in queryset: if item.product not in seen_products: seen_products.add(item.product) unique_products.append(item) if len(unique_products) == 3: break
验证结果
两种方案最终都会返回你期望的结果:
brand product flavour sodium 7 03 chips salt 23 4 02 cream herbs 17 2 01 twister Cheese 15
内容的提问来源于stack exchange,提问作者Russgo
相关产品推荐
相关产品推荐

