Django:过滤带注释的结果
我有两个模型:
class Status(models.Model):
title = models.CharField(max_length=32)
class Task(models.Model):
user = models.ForeignKey(User)
status = models.ForeignKey(Status, default=1)
title = models.CharField(max_length=128)
我想创建一个导航列表,其中包含我的状态模型中的所有状态,例如:今天、明天、等待、已计划、垃圾箱
足够简单。然后,我想显示分配给每个状态的任务数量,感谢 SO,也很简单:
Status.objects.all().annotate(Count('task'))
这很好地创建了我所有状态的列表以及分配给每个状态的任务数量:
今天 (1) 明天 (1) 等待 (0) 预定 (2) 垃圾(7)
所有这些的技巧现在是如何过滤上述值,以便它们仅反映当前登录的用户。向查询集中添加过滤器似乎会删除任何有意义的零状态。不过我想要那些零状态。我当前的想法涉及Q()
:
Status.objects.filter(Q(task__user=1) | Q(task__user__isnull=True)).annotate(Count('task'))
这不起作用。
有什么想法吗?
为 Yuji 编辑
Status.objects.all().annotate(Count('task'))
给出:
收件箱 (3) 今天 (0) 下一页 (1) 等待 (0) 预定 (1) 稍后 (0) 有一天 (0) 档案 (0) 垃圾 (0)
很好,但其中 1 个收件箱任务和计划任务是为其他用户准备的。好的,让我们尝试过滤。
Status.objects.filter(task__user=current_user).annotate(Count('task'))
收件箱 (2) 下一篇(1)
有效!有点……我的(我这样称呼他们)清零状态不存在。我应该说,任何没有与之关联的任务的状态都不会显示,因为当前登录的用户不会显示。我想让它出现。
I have two models:
class Status(models.Model):
title = models.CharField(max_length=32)
class Task(models.Model):
user = models.ForeignKey(User)
status = models.ForeignKey(Status, default=1)
title = models.CharField(max_length=128)
I want to create a nav list that contains all of the statuses I have in my status model, example: Today, Tomorrow, Waiting, Scheduled, Trash
Simple enough. I then want to display the number of tasks assigned to each status, thanks to SO, also simple:
Status.objects.all().annotate(Count('task'))
This nicely creates a list of all of my statuses and a number the number of tasks assigned to each:
Today (1)
Tomorrow (1)
Waiting (0)
Scheduled (2)
Trash (7)
The trick with all of this is now how to filter the above values so that they only reflect the current logged in user. Adding a filter to the queryset seems to remove any zero statuses which makes sense. I want those zero statuses though. My current idea involves Q()
:
Status.objects.filter(Q(task__user=1) | Q(task__user__isnull=True)).annotate(Count('task'))
This does not work.
Any ideas?
Edit for Yuji
Status.objects.all().annotate(Count('task'))
Gives:
Inbox (3)
Today (0)
Next (1)
Waiting (0)
Scheduled (1)
Later (0)
Someday (0)
Archives (0)
Trash (0)
Great but 1 of those inbox tasks and scheduled are for another user. Ok, so let's try filtering.
Status.objects.filter(task__user=current_user).annotate(Count('task'))
Inbox (2)
Next (1)
Works! Sorta.... My (as I called them) zero'ed out statuses aren't there. I should say, any status that doesn't have a task associated with it as that currently logged in user does not show up. I want it to show up.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这应该为您提供属于该用户的所有任务对象的计数。
添加过滤器会删除任何零状态是什么意思?
添加用户过滤器将获取与该用户关联的所有任务对象,无论状态如何(0 或您拥有的状态)。
This should give you a count of all Task objects belonging to the User by count.
What do you mean adding a filter removes any zero statuses?
Adding the user filter would get all Task objects that are associated with the User, regardless of Status (0 or what have you).
Status.objects.annotate(Count('task')).filter(task__user=current_user)
有效吗?您想要的是,在 SQL 级别,
LEFT JOIN
或类似的东西,Status
表位于左侧,而不是INNER JOIN
。但不确定它如何与注释交互。如果其他方法都失败,则暴力破解是
[stat.filter(task__user=current_user).count() for stat in Status.objects.all()]
,但这是 N 次查询,而不是 1 次。Does
Status.objects.annotate(Count('task')).filter(task__user=current_user)
work?What you want is, at the SQL level, a
LEFT JOIN
or somesuch, with theStatus
table on the left, rather than anINNER JOIN
. Not sure how that interacts with annotations, though.Brute force is
[stat.filter(task__user=current_user).count() for stat in Status.objects.all()]
if all else fails, but that's N queries instead of one.好吧...我认为实现此目的的唯一方法是使用 LEFT OUTER JOIN 或 SUBQUERY s...我不知道如何表达左外连接在 django 中,所以我将使用
SUBQUERY
路径。下面将使用extra
和一些手工编写的 SQL,享受吧!请注意,我使用了很多...未记录的功能(例如:Task._meta),这些功能将来可能会中断(希望不会)...但是,嘿,他们完成了这项工作。
Well... the only way I think you can achieve this is with
LEFT OUTER JOIN
s orSUBQUERY
s... I have no idea on how to express left outer joins in django, so I'll go with theSUBQUERY
path. The following will useextra
with some handcrafted SQL, enjoy!Note that I'm using a lot of... undocumented features (for instance: Task._meta), these might break in the future (let's hope not)... but hey, they do the job.