【问题标题】:I'm confused about how distinct() works with Django queries我对 distinct() 如何与 Django 查询一起工作感到困惑
【发布时间】:2011-11-23 22:39:19
【问题描述】:

我有这个问题:

checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location)

这对于告诉我在特定位置的日期范围内发生了多少签入非常有用。但我想知道唯一用户完成了多少签入。所以我尝试了这个:

checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location).values('user').distinct()

但这不起作用,我返回一个空数组。任何想法为什么?

这是我的 CheckinAct 模型:

class CheckinAct(models.Model):
    user = models.ForeignKey(User)
    location = models.ForeignKey(Location)
    time = models.DateTimeField()

----更新----- 所以现在我将查询更新为如下所示:

 checkins = CheckinAct.objects.values('user').\
                            filter(time__range=[start, end], location=checkin.location).\
                            annotate(dcount=Count('user'))

但我仍然得到多个具有相同用户的对象,如下所示:

 [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}]

---- 更新 2------ 这是我尝试过的其他方法,但是当我登录 checkins 对象时,我仍然得到很多相同的用户对象。

checkins = CheckinAct.objects.filter(
                    time__range=[start, end],
                    location=checkin.location,
                ).annotate(dcount=Count('user')).values('user', 'dcount')
        logger.info("checkins!!! : " + str(checkins))

记录以下内容:

checkins!!! : [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}]

注意同一个用户对象有 3 个实例。这是否正常工作?是否有不同的方式来读取 dict 对象中返回的内容?我只需要知道在该时间范围内有多少唯一身份用户签入该特定位置。

【问题讨论】:

  • distinct 只是消除了重复的结果(就像在相同的所有内容中一样,甚至是pk)。它不会使结果对于一个或另一个领域是唯一的。您可能正在寻找这个:stackoverflow.com/questions/629551/…
  • 感谢克里斯的评论,我想我越来越近了,感谢您为我指明了正确的方向。我已经更新了我的帖子。

标签: django django-queryset django-nonrel


【解决方案1】:

答案其实就在Django docs。不幸的是,很少有人注意到您需要的特定部分的重要性。所以这是可以理解的错过。 (仔细阅读与Items 打交道的部分。)

对于您的用例,以下内容应该可以满足您的需求:

checkins = CheckinAct.objects.filter(time__range=[start,end], location=checkin.location).\
                              values('user').annotate(checkin_count=Count('pk')).order_by()

更新

根据您的评论,我认为您想要实现的问题一直很困惑。上面的查询为您提供的是每个用户在某个位置签到的次数列表,所述列表中没有重复的用户。现在看来,您真正想要的是在一个特定位置签到的唯一用户数。要做到这一点,请使用以下内容(无论如何都要简单得多):

User.objects.filter(checkinat__location=location).distinct().count()

非相关支持的更新

checkin_users = [(c.user.pk, c.user) for c in CheckinAct.objects.filter(location=location)]
unique_checkins = len(dict(checkin_users))

这不符合dicts 具有唯一键的原则。因此,当您将元组列表转换为字典时,您最终会得到一个唯一用户列表。 但是,这将生成 1*N 个查询,其中 N 是签入的总数(每次使用 user 属性时一个查询。通常,我会做类似.select_related('user') 的事情,但这也需要一个 JOIN,这显然已经过时了。不支持的 JOIN 似乎是 non-rel 的一个巨大缺点,如果是这样的话,但如果是这样的话,这将是你唯一的选择。

【讨论】:

  • 我得到 checkins 对象后,如何知道有多少个唯一用户?我认为这个查询可能给了我我需要的东西,但我不知道如何从中获取唯一用户的数量。当我刚刚输入 str(checkins) 时,我得到了重复项,如下所示: [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {' user': 17462L}, {'user': 15521L}] 那么我该如何读出唯一用户的数量?
  • 我认为您所指的内容适用于支持连接的数据库。由于我在 Django non-rel 上,我收到此错误:“此数据库不支持 JOIN 和多表继承。”
  • 哦。哎哟。好吧,它仍然可以完成,但需要额外的查询。查看更新。
  • 克里斯。就是这样。谢谢你的帮助!一个快速的最后一个问题。我将查找元组的转换列表以更好地理解这一点。
【解决方案2】:

你不想要DISTINCT。你实际上希望 Django 做一些最终会给你一个GROUP BY 子句的事情。您的最终解决方案是结合annotate()values() 也是正确的,正如in the Django documentation 所讨论的那样。

你想要得到你的结果是先用annotate,然后用values,比如:

CheckinAct.objects.filter(
    time__range=[start, end],
    location=checkin.location,
).annotate(dcount=Count('user').values('user', 'dcount')

我在上面给你的链接中的 Django 文档显示了一个类似构造的查询(减去filter 方面,我在适当的位置为你的情况添加了它),并注意这将“现在产生一个独特的结果每个 [checkin act];但是,只有 [user] 和 [dcount] 注释将在输出数据中返回”。 (我修改了句子以适合您的情况,但原理是一样的)。

希望有帮助!

【讨论】:

  • 我尝试了您提出的内容,并更新了我的问题。我仍然认为它不起作用。
【解决方案3】:
checkins = CheckinAct.objects.values('user').\
                        filter(time__range=[start, end], location=checkin.location).\
                        annotate(dcount=Count('user'))

如果我没记错的话,你想要的值在输入中不是“dcount”吗?结果,当你决定单独输出用户值时,不就是被丢弃了吗?

你能告诉我当你尝试这个时会发生什么吗?

checkins = CheckinAct.objects.values('user').\
                        filter(time__range=[start, end], location=checkin.location).\
                        annotate(Count('user')).order_by()

(最后一个 order_by 是清除您在模型级别可能已经拥有的任何内置排序 - 不确定您是否有类似的东西,但问一下也无妨……)

【讨论】:

  • 我试过你放的东西,但是当我做 str(checkins) 时,看起来我仍然多次出现同一个用户。 “签到:[{'user': 15521L}, {'user': 15521L}, {'user': 15521L}]”
猜你喜欢
  • 2014-02-14
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多