我有两种模式:
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)
很好,但其中一个收件箱任务和预定的是另一个用户。好的,让我们尝试过滤。
Status.objects.filter(task__user=current_user).annotate(Count('task'))
收件箱(2) 下一步(1)
作品! Sorta ....我(我称之为)零状态不存在。我应该说,任何没有与当前登录用户相关联的任务的状态都不会显示。我希望它出现。
答案 0 :(得分:0)
这应该按计数为您计算属于User的所有Task对象。
Status.objects.filter(task__user=current_user).annotate(Count('task'))
您是什么意思添加过滤器会删除任何零状态?
添加用户过滤器将获得与用户关联的所有Task对象,而不管状态(0或您有什么)。
答案 1 :(得分:0)
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个查询而不是一个。
答案 2 :(得分:0)
嗯......我认为你可以实现这一目标的唯一方法是使用LEFT OUTER JOIN
s或SUBQUERY
s ...我不知道如何在django中表达左外连接,所以我我会选择SUBQUERY
路径。以下将使用extra
和一些手工制作的SQL,享受!
# you should have Task and Status imported
x = Status.objects.extra(select = {
"task__count" : "SELECT COUNT(*) FROM %(task_table)s WHERE %(task_table)s.%(task_status_id)s = %(status_table)s.%(status_pk)s AND %(task_table)s.%(user_col)s = %(user_id)d" %
{
"task_table" : Task._meta.db_table,
"task_status_id" : Task._meta.get_field_by_name("status")[0].column,
"status_table" : Status._meta.db_table,
"status_pk" : Status._meta.pk.column,
"user_col" : Task._meta.get_field_by_name("user")[0].column,
"user_id" : 1
}
})
请注意,我使用了很多......未记录的功能(例如:Task._meta),这些功能可能会在将来中断(我们希望不会这样)......但是,嘿,他们会完成这项工作。