如何通过Django QuerySet按销量排序获取Top10畅销商品
问题描述
需要从分属不同应用的模型中获取销量Top10的商品,现有模型结构如下:
Product模型
class Product(models.Model): user = models.ForeignKey(Vendor, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE) ubcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE, blank=True, null=True) product_name = models.CharField(max_length=100) product_slug = models.SlugField(max_length=100, unique=True)
SoldProduct模型(记录已售商品)
class SoldProduct(models.Model): order = models.ForeignKey(Order, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='soldproducts') quantity = models.IntegerField()
目前已通过以下QuerySet获取商品PK和销量总和:
best_seller_products = SoldProduct.objects.filter(product__in=products, order__in=orders).values( 'product__pk',).annotate(qty=Sum('quantity')).order_by('-qty')[:6]
查询结果示例:
<QuerySet [{'product__pk': 5, 'qty': 22}, {'product__pk': 6, 'qty': 6}]>
随后通过PK获取商品列表:
best_seller_products = products.filter(pk__in=list_best_seller_products_pk)
需要解决的问题:如何将该商品列表按对应销量排序?优先采用查询方式,不在Product模型新增sold字段。
解决方案
方案一:数据库层面直接查询并排序(优先推荐)
直接从Product模型出发,通过反向关联(soldproducts是SoldProduct中定义的related_name)筛选符合条件的商品,同时标注总销量并排序,一步到位得到已按销量排序的Product实例集合:
best_seller_products = Product.objects.filter( pk__in=products, # 保留你原本的Product筛选范围 soldproducts__order__in=orders # 关联订单筛选条件 ).annotate( total_sales=Sum('soldproducts__quantity') ).order_by('-total_sales')[:10] # 按总销量倒序,取Top10
优势
- 数据库层面完成筛选、统计和排序,性能更优,尤其适合数据量较大的场景
- 直接返回排序后的
Product实例,无需后续内存中二次处理
方案二:内存中基于销量映射排序(兼容现有两步查询逻辑)
如果必须保留先获取销量PK映射、再查询商品的逻辑,可以将销量数据转成字典,用Pythonsorted函数完成排序:
# 第一步:获取商品PK与销量的映射字典 sales_map = {item['product__pk']: item['qty'] for item in best_seller_products} # 第二步:查询商品并按销量排序 sorted_products = sorted( products.filter(pk__in=sales_map.keys()), key=lambda product: sales_map[product.pk], reverse=True # 倒序排列,销量高的在前 )
说明
- 适合无法修改初始查询逻辑的场景,但数据量大时内存排序效率不如数据库层面处理
内容的提问来源于stack exchange,提问作者RMCode
相关产品推荐
相关产品推荐

