【问题标题】:Ordering objects by rating accounting for the number or ratings根据数量或评级按评级排序对象
【发布时间】:2015-10-15 05:53:02
【问题描述】:

我正在尝试执行类似于此 SO 问题中的第一个响应:SQL ordering by rating/votes,其中可以对资源进行评级(每个用户每个资源一个评级),但是在根据其评级对资源进行排序时,任何资源小于 X 的单独评分将显示在具有 X 或更多的评分下方。

我在 Django 中实现这一点,我非常希望避免使用原始查询并保留在 Django 模型和查询框架中。

到目前为止,这就是我所拥有的:

data = []
data_top = Resource.objects.all().annotate(rating=Avg('resourcerating__rating'),rate_count=Count('resourcerating')).exclude(rate_count__lt=settings.ORB_RESOURCE_MIN_RATINGS).order_by(order_by)
for d in data_top:
    data.append(d)

data_bottom = Resource.objects.all().annotate(rating=Avg('resourcerating__rating'),rate_count=Count('resourcerating')).exclude(rate_count__gte=settings.ORB_RESOURCE_MIN_RATINGS).order_by(order_by)
for d in data_bottom:
    data.append(d)

这所有功能并根据我的需要返回按评级排序,但是,感觉效率不高 - 运行 2 个查询并循环遍历每个查询的结果。

有没有更好的方法可以在单个查询中进行编码,或者至少避免在每个查询集中循环?

非常感谢任何帮助。

【问题讨论】:

    标签: python django django-models


    【解决方案1】:
    from itertools import chain
    
    main_query = Resource.objects.all().annotate(rating=Avg('resourcerating__rating'),rate_count=Count('resourcerating'))
    
    data_top_query = main_query.exclude(rate_count__lt=settings.ORB_RESOURCE_MIN_RATINGS).order_by(order_by)
    data_bottom_query = main_query.exclude(rate_count__gte=settings.ORB_RESOURCE_MIN_RATINGS).order_by(order_by)
    
    data = list(chain(data_top_query, data_bottom_query))
    

    使用 itertools.chain 比循环每个列表并逐个添加元素要快

    此外,查询集将在调用 list 时进行评估(因为直到那时它们才访问数据库)

    仅供参考,上述内容在评估时会命中数据库两次。

    【讨论】:

      【解决方案2】:

      您当前查询了两次并迭代了两次,但您可以轻松地将其缩减为一个和一个 - 只需查询按评级排序的项目,然后像这样迭代:

      data_top = []
      data_bottom = []
      data = Resource.objects.all().annotate(rating=Avg('resourcerating__rating'),rate_count=Count('resourcerating')).order_by(order_by)
      for d in data:
          if data.rate_count >= settings.ORB_RESOURCE_MIN_RATINGS:
              data_top.append(d)
          else:
              data_bottom.append(d)
      
      data = data_top + data_bottom 
      

      这也可以仅通过查询来完成,方法是创建另一个包含值 rate_count < settings.ORB_RESOURCE_MIN_RATINGS 的聚合列(对于高于或等于阈值的值返回 0,对于低于阈值的值返回 1)并按 (new_column, rating) 排序。很确定这需要一些自定义 SQL,但也许其他人不知道。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-03
        • 1970-01-01
        • 2020-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-27
        相关资源
        最近更新 更多