我对 unique() 如何与 Django 查询一起使用感到困惑

发布于 2024-12-17 17:48:29 字数 1534 浏览 2 评论 0原文

我有这样的查询:

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

I have this query:

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

Which works great for telling me how many checkins have happened in my date range for a specific location. But I want know how many checkins were done by unique users. So I tried this:

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

But that doesn't work, I get back an empty Array. Any ideas why?

Here is my CheckinAct model:

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

----Update------
So now I have updated my query to look like this:

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

But I'm still getting multiple objects back that have the same user, like so:

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

---- Update 2------
Here is something else I tried, but I'm still getting lots of identical user objects back when I log the checkins object.

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

Logs the following:

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

Notice how there are 3 instances of the same user object. Is this working correctly or not? Is there a difference way to read out what comes back in the dict object? I just need to know how many unique users check into that specific location during the time range.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我的奇迹 2024-12-24 17:48:29

答案实际上在 Django 文档 中是正确的。不幸的是,很少有人注意到您需要的特定部分的重要性;所以它被错过是可以理解的。 (稍微阅读一下处理 Item 的部分。)

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

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

UPDATE for non-rel support

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

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

The answer is actually right in the Django docs. Unfortunately, very little attention is drawn to the importance of the particular part you need; so it's understandably missed. (Read down a little to the part dealing with Items.)

For your use-case, the following should give you exactly what you want:

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

UPDATE

Based on your comment, I think the issue of what you wanted to achieve has been confused all along. What the query above gives you is a list of the number of times each user checked in at a location, without duplicate users in said list. It now seems what you really wanted was the number of unique users that checked in at one particular location. To get that, use the following (which is much simpler anyways):

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

UPDATE for non-rel support

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

This works off the principle that dicts have unique keys. So when you convert the list of tuples to a dict, you end up with a list of unique users. But, this will generate 1*N queries, where N is the total amount of checkins (one query each time the user attribute is used. Normally, I'd do something like .select_related('user'), but that too requires a JOIN, which is apparently out. JOINs not being supported seems like a huge downside to non-rel, if true, but if that's the case this is going to be your only option.

够运 2024-12-24 17:48:29

您不需要DISTINCT。您实际上希望 Django 做一些最终会给您一个 GROUP BY 子句的事情。您的最终解决方案是结合 annotate()values(),正如所讨论的 位于 Django 文档

要获得结果,您需要首先使用 annotate,然后使用 values,例如:

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

我上面给您的链接中的 Django 文档显示了类似的构造查询(减去 filter 方面,我在适当的位置为您的案例添加了该方面),并请注意,这将“现在为每个 [签入行为] 生成一个唯一的结果;但是,只有 [用户] 和 [dcount]注释将在输出数据中返回”。 (我编辑了这句话以适合您的情况,但原理是相同的)。

希望有帮助!

You don't want DISTINCT. You actually want Django to do something that will end up giving you a GROUP BY clause. You are also correct that your final solution is to combine annotate() and values(), as discussed in the Django documentation.

What you want to do to get your results is to use annotate first, and then values, such as:

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

The Django docs at the link I gave you above show a similarly constructed query (minus the filter aspect, which I added for your case in the proper location), and note that this will "now yield one unique result for each [checkin act]; however, only the [user] and the [dcount] annotation will be returned in the output data". (I edited the sentence to fit your case, but the principle is the same).

Hope that helps!

瀟灑尐姊 2024-12-24 17:48:29
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 是清除您在模型级别可能已经拥有的任何内置排序 - 不确定您是否有类似的东西,但问一下也没什么坏处......)

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

If I am not mistaken, wouldn't the value you want be in the input as "dcount"? As a result, isn't that just being discarded when you decide to output the user value alone?

Can you tell me what happens when you try this?

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

(The last order_by is to clear any built-in ordering that you may already have at the model level - not sure if you have anything like that, but doesn't hurt to ask...)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文