【问题标题】:How to sort a Django queryset by a conditional aggregation of related items?如何通过相关项目的条件聚合对 Django 查询集进行排序?
【发布时间】:2016-02-22 09:08:48
【问题描述】:

如何使用 Django ORM 通过相关项的条件 聚合对查询集中的所有对象进行排序? Django 1.8 及更高版本明确具有conditional aggregation support,我需要 Django 的答案。这显然会涉及 3 或 4 个查询。以下是回答者可以用来说明其回答的示例模型:

class Group(models.Model):
    owner = models.ForeignKey(User)
    created_at = models.DateTimeField(auto_now_add=True)

class GroupTraffic(models.Model):
    visitor = models.ForeignKey(User)
    which_group = models.ForeignKey(Group)
    time_of_visit = models.DateTimeField(auto_now_add=True)

用户拥有聊天群,其他用户可以访问该聊天群。要回答的问题是:如何生成所有组的排序列表,以便按每个组在最近 60 个中看到的唯一流量排序分钟?在过去 60 分钟内看到大量唯一身份访问者的组会排在顶部,此类流量几乎为零(或零)的组会出现在列表底部。

这是一个条件聚合问题,因为从本质上讲,我们需要为每个组对象注释过去 60 分钟内记录的所有相关的、唯一的组流量对象的计数。

有人可以告诉我如何使用 Django ORM 来解决 = 1.8(感谢this),我不想通过原始或额外的 SQL 查询来实现。

【问题讨论】:

  • 通过唯一流量,我的意思是如果它是具有相同 ID 的访问者,则不会重复计算。 IE。在 Django ORM 中使用 distinct
  • 到目前为止您尝试过哪些查询?
  • 大名单人,等一下,我会放一些最接近的。
  • 查询1:这个没有考虑过去60分钟的流量:groups = Group.objects.annotate(views=Count('grouptraffic__visitor', distinct=True))
  • 查询 2:这些没有考虑到所有组:date = datetime.now()-timedelta(hours=1)new_traff = GroupTraffic.objects.filter(time__gte=date, which_group__private='0').distinct('visitor').values_list('id',flat=True)trendingGrp_ids = GroupTraffic.objects.filter(id__in=new_traff).values('which_group').annotate(total=Count('which_group')).order_by('-total')trendingGrps = [Group.objects.filter(id=grp['which_group']).extra(select={"views":grp['total']})[0] for grp in trendingGrp_ids]return trendingGrps

标签: python django sorting django-queryset django-orm


【解决方案1】:

只需过滤time_of_visit,它应该可以正常工作:

one_hour_ago = datetime.now()-timedelta(hours=1)
recent_groups = Group.objects.filter(grouptraffic__time_of_visit>=one_hour_ago)
visitors = recent_groups.annotate(views=Count('grouptraffic__visitor', distinct=True))

然后获取所有较旧的组,并为空视图使用 extra 字段:

older_groups = Group.objects.filter(grouptraffic__time_of_visit < one_hour_ago).extra(select={'visits':0})

然后用管道将它们连接在一起:

all_groups = visitors | older_groups 

【讨论】:

  • 不包括组在过去一小时内没有记录访问吗?我想包括所有组,只是那些在过去一个小时内没有访问的组应该排在最后。
  • 好的,还有一个要求是首先按 hottest 组对列表进行排序。我应该直接在“all_groups”上运行“order_by('-views')”吗?
  • 应该可以。如果没有,您可以单独对每个查询进行排序,然后合并。
  • 好吧。我正在试一试,从逻辑上讲,这是可行的。我过会儿再来汇报。
  • 顺便说一句,那应该是all_groups = visitors | older_groups,不是吗?
猜你喜欢
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多