当状态为ManyToManyField时,按当前状态类型过滤项目

时间:2011-10-25 15:09:44

标签: django

有关背景,请参阅此问题:Returning the current project status (i.e., most recent date on Django ManyToMany relationship)

当我在思考这个问题时,它引发了一个我自己的问题。基本上,你有类似于以下内容的东西:

class StatusType(models.Model):
    name = models.CharField(max_length=64)

class Project(models.Model):
    status = models.ManyToManyField(StatusType, through='ProjectStatusType')

class ProjectStatusType(models.Model):
    project = models.ForeignKey(Project)
    status_type = models.ForeignKey(StatusType)
    created = models.DateTimeField(auto_now_add=True)

要获取特定项目的当前状态类型,您可以执行以下操作:

Project.status.order_by('-projectstatustype__created')[0]

但是如果你想获得当前状态为'foo'的所有项目怎么办?

Project.objects.filter(status__name='foo')

这将返回曾经拥有'foo'状态的项目,无论它是否是当前状态。你几乎想做类似的事情(注意在过滤器中使用current):

Project.objects.annotate(current=Max('projectstatustype__created')).filter(status__name='foo', projectstatustype__created=current)

显然,这不起作用,因为在那个上下文中,current应该是当前范围内的Python变量,但它让我感到疑惑:是否有某种方法可以将相同的概念传递给SQL,它会查找与刚刚创建的注释匹配的创建日期吗?

更新

@akonsu建议简单地使用ProjectStatusType模型。然而,这并没有真正解决任何问题。

ProjectStatusType.objects.filter(statustype__name='foo')

返回状态为“foo”的所有ProjectStatusType。然后,您可以遍历查询集并使用Project属性获取每个project,但同样,这些项目将在某个时间点具有此状态,不一定是具有此状态的项目目前。即使你尝试过类似的东西:

ProjectStatusType.objects.filter(statustype__name='foo').order_by('-created')[0]

然后访问project属性,这只会为您提供最近收到此状态的项目,而不是所有当前具有该状态的项目。

2 个答案:

答案 0 :(得分:4)

基本上问题是如何通过比较两个字段来过滤查询集:https://docs.djangoproject.com/en/dev/topics/db/queries/#filters-can-reference-fields-on-the-model

因此可以修复使用注释的原始查询:

Project.objects.annotate(current=Max('projectstatustype__created'))
               .filter(status__‌​name='foo',
                       projectstatustype__created=F('current'))

答案 1 :(得分:0)

可能有一个有多个连接和聚合的工作解决方案,但我想到非规范化:只需将cur_status字段添加到Project并用信号更新它。