我对于distinct()如何处理Django查询感到困惑

时间:2011-11-23 22:39:19

标签: django django-queryset django-nonrel

我有这个问题:

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对象中的内容?我只需要知道有多少唯一身份用户在该时间范围内检查该特定位置。

3 个答案:

答案 0 :(得分:1)

答案实际上在Django docs。不幸的是,很少关注你需要的特定部分的重要性;所以这是可以理解的错过了。 (稍微阅读处理Item s的部分。)

对于您的用例,以下内容应该为您提供您想要的内容:

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))

这符合dict具有唯一键的原则。因此,当您将元组列表转换为dict时,最终会得到一个唯一用户列表。 但是,这将生成1 * N个查询,其中N是签入的总量(每次使用user属性时一个查询。通常,我会执行类似{{{{ 1}},但是这也需要一个JOIN,显然已经出局了。如果没有,那么JOIN不受支持似乎是非强烈的巨大的缺点,但是如果是这样的话,那将会是你唯一的选择。

答案 1 :(得分:0)

您不希望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]注释将在输出数据中返回“。 (我编辑了句子以适合你的情况,但原则是一样的。)

希望有所帮助!

答案 2 :(得分:0)

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是为了清除你在模型级别可能已经拥有的任何内置顺序 - 不确定你是否有类似的东西,但是不会有问题......)