Django:过滤带注释的结果

时间:2011-02-07 00:35:18

标签: python django django-orm

我有两种模式:

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 ....我(我称之为)零状态不存在。我应该说,任何没有与当前登录用户相关联的任务的状态都不会显示。我希望它出现。

3 个答案:

答案 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),这些功能可能会在将来中断(我们希望不会这样)......但是,嘿,他们会完成这项工作。