如何编写Django查询按平均评分与评论数降序获取产品对象?
获取Django中顶级评分产品的查询方案
模型定义
class Product(models.Model): user = models.ForeignKey(User, verbose_name=_("Owner"), on_delete=models.CASCADE) name = models.CharField(_("Name"), max_length=150,null=True) average_rating = models.DecimalField(_("average rating"), max_digits=10, decimal_places=2,null=True,blank=True) total_reviews = models.IntegerField(_("total reviews "),default=0,null=True,blank=True) is_remove = models.BooleanField(_("Remove"), default=False) create_time = models.DateTimeField(_("Create time"), default=timezone.now)
需求
获取所有平均评分最高且评论总数最多的产品对象。
现有方案问题分析
方案1
def get_all_top_rated_products(self): query = self.filter(is_remove=False).order_by("total_reviews","average_rating") print(query) return query
- 默认升序排序,返回的是评分最低、评论最少的产品,完全不符合需求;即使改成降序,也只是排序结果,无法精准筛选出同时满足两个条件的产品。
方案2
def get_all_top_rated_products(self): query = self.filter(is_remove=False).aggregate(Max('average_rating'),Max('total_reviews')) print(query) return query
aggregate返回的是包含最大评分、最大评论数的字典,不是产品对象集合,无法直接拿到对应的产品数据。
正确实现方案
方案A:严格筛选同时满足最高评分+最多评论的产品
def get_all_top_rated_products(self): # 先限定有效产品(未被删除) valid_products = self.filter(is_remove=False) # 获取最高评分和最多评论数的数值 max_rating = valid_products.aggregate(Max('average_rating'))['average_rating__max'] max_reviews = valid_products.aggregate(Max('total_reviews'))['total_reviews__max'] # 处理评分可能为空的情况 if max_rating is not None: top_products = valid_products.filter( average_rating=max_rating, total_reviews=max_reviews ) else: # 若所有产品无评分,仅筛选评论最多的 top_products = valid_products.filter(total_reviews=max_reviews) return top_products
方案B:先取评分最高的产品集合,再从中筛选评论最多的
如果你的需求是「先以平均评分为第一优先级,取所有评分最高的产品,再在这些产品里找评论数最多的」,可以用这个方案:
def get_all_top_rated_products(self): valid_products = self.filter(is_remove=False).order_by('-average_rating', '-total_reviews') if not valid_products.exists(): return valid_products # 获取最高评分值 top_rating = valid_products.first().average_rating # 筛选所有最高评分的产品 top_rating_products = valid_products.filter(average_rating=top_rating) # 获取这批产品中的最多评论数 max_reviews_in_top = top_rating_products.aggregate(Max('total_reviews'))['total_reviews__max'] return top_rating_products.filter(total_reviews=max_reviews_in_top)
内容的提问来源于stack exchange,提问作者Ahmed Yasin
相关产品推荐
相关产品推荐

