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

发布于 2024-12-11 13:39:16 字数 1761 浏览 0 评论 0原文

有关背景信息,请参阅此问题: 返回当前项目状态(即 Django ManyToMany 关系的最新日期)

当我思考这个问题时,它引发了我自己的一个问题。本质上,您的内容大致类似于以下内容:

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 属性,也只会为您提供最近收到此状态的项目,而不是当前具有此状态的所有项目。

For background see this SO question: Returning the current project status (i.e., most recent date on Django ManyToMany relationship)

As I was thinking about the problem, it sparked a question of my own. Essentially, you have something roughly similar to the following:

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)

To get the current status type for a particular project, you could do something like:

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

But what if you wanted to get all projects whose current status is 'foo'?

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

That would return projects who ever had a status of 'foo', whether or not it was the current status. You almost want to do something like (note the use of current in the filter):

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

Obviously, that won't work because in that context, current is expected to be a Python variable within the current scope, but it got me wondering: is there some way to pass the same concept on though to the SQL, such that it will look for created dates that match the annotation that was just created?

UPDATE:

It was suggested by @akonsu to simply use the ProjectStatusType model, instead. However that doesn't really solve anything.

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

Returns all ProjectStatusType with a status of 'foo'. You could then loop over the queryset and get each Project with the project attribute, but again, these will be projects that at some point in time had this status, not necessarily projects that have this status currently. Even if you tried something like:

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

And then accessed the project attribute, that would merely give you the project that most recently received this status, not all projects that currently have the status.

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

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

发布评论

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

评论(2

谜兔 2024-12-18 13:39:16

基本上问题是如何通过比较查询集的两个字段来过滤查询集: 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'))

basically the question is how to filter a query set by comparing two of its fields: https://docs.djangoproject.com/en/dev/topics/db/queries/#filters-can-reference-fields-on-the-model.

so your original query that uses annotations can be fixed:

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

就像说晚安 2024-12-18 13:39:16

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

May be there is a working solution with multiple joins and aggregation, but I'd think about denormalization: just add cur_status field to Project and update it with signals.

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