返回当前项目状态(即 Django ManyToMany 关系的最新日期)

发布于 2024-12-11 19:28:07 字数 705 浏览 0 评论 0原文

架构描述

项目的状态可能会随着时间的推移而改变。为了跟踪一段时间内的状态,我通过 ProjectStatusProject 模型和 ProjectStatusType 模型之间创建了多对多关系代码>中间表。

虽然这允许随着时间的推移跟踪项目的状态,但它增加了模式的复杂性,使得检索项目的当前状态或检索所有打开的项目变得更加困难。

在此处输入图像描述

用例

我希望能够返回处于给定状态的所有项目,例如所有 <代码>打开项目。例如,当用户访问 http://www.example.com/projects 时,我会就像默认情况下仅在表格中显示打开项目一样。

问题

  1. 我是否应该对架构进行非规范化并在 Project 模型中添加 current_status 字段?
  2. 如果我不应该反规范化,我应该使用什么策略来检索每个项目的当前状态?我应该在 Project 模型上创建一个属性来检索当前状态吗?

Schema Description

A project's status can change over time. In order to track the status over time, I've created a many-to-many relationship between the Project model and the ProjectStatusType model through the ProjectStatus intermediary table.

While this allows tracking a project's status over time, it increases the complexity of the schema such that retrieving the current status of a project or retrieving all open projects is more difficult.

enter image description here

Use Case

I want to be able to return all projects that are in a given state, such as all open projects. For instance, when users go to http://www.example.com/projects, I'd like only the open projects to be displayed in a table by default.

Questions

  1. Should I denormalize the schema and add a current_status field in the Project model?
  2. If I shouldn't denormalize, what strategy should I use to retrieve the current status for each project? Should I create a property on the Project model that retrieves the current status?

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

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

发布评论

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

评论(2

为你鎻心 2024-12-18 19:28:07

如果您不需要搜索它,我会在项目模型上创建一个属性。您可以使用Max函数进行聚合来获取最新日期的记录。

from django.db.models import Max

class Project(models.Model):
    [...]

    @property
    def status_date(self):
        return self.projectstatus_set.aggregate(newest=Max('status_date'))['newest']

此策略记录在此处

如果您需要进行查找,那么您应该反规范化并向 Project 添加一个字段。您可以使用信号使其保持最新状态。您需要向 ProjectStatus 字段添加一个 post_save 侦听器,这会将其项目的日期设置为“状态”。

from django.db.signals import post_save

def update_status_date(sender, instance=None, **kwargs):
    project = instance.project
    project.status_date = max(project.status_date, instance.status_date)
    project.save()
post_save.connect(update_status_date, sender=ProjectStatus)

您可以在此处了解有关信号的更多信息。

======

编辑:自从写下我原来的答案以来,OP 已经在一定程度上澄清了他的问题,他的澄清改变了我的两种策略的示例代码,尽管不是它们的基本结构。我想把原来的答案留给那些可能需要更多类似于我当时想回答的问题的人。

在我的第一个示例中,他实际上并不想要最新的 status_date 本身,而是想要最新的项目状态类型。这将极大地改变财产;您根本不需要使用 MAX() SQL 构造;您只希望按日期降序排列时附加到该对象的第一条记录:

class Project(models.Model):
    [...]

    @property
    def project_status(self):
        return self.status.order_by('-status_date')[0]

围绕此的用例仍然相同。如果您总是先获得一个项目,然后想了解其当前状态,那么这是正确的方法。如果您需要按状态对项目进行索引,那么您需要非规范化。这仍然最好通过信号来完成,但您可能想保存描述,而不是像我在上面的示例中所做的那样保存日期。但原理仍然是一样的。

If you don't need to search on it, I would create a property on the Project model. You can use the Max function to aggregate to get the record with the newest date.

from django.db.models import Max

class Project(models.Model):
    [...]

    @property
    def status_date(self):
        return self.projectstatus_set.aggregate(newest=Max('status_date'))['newest']

This strategy is documented here.

If you need to do lookups, then you should denormalize and add a field to Project. You can keep it current using signals. You would want to add a post_save listener to your ProjectStatus field, which would set its project's date to the status'.

from django.db.signals import post_save

def update_status_date(sender, instance=None, **kwargs):
    project = instance.project
    project.status_date = max(project.status_date, instance.status_date)
    project.save()
post_save.connect(update_status_date, sender=ProjectStatus)

You can read more about signals here.

======

EDIT: Since writing my original answer, the OP has clarified his question somewhat, and his clarification alters the example code for both of my strategies, although not their basic construction. I want to leave the original answer for those who may have needs more akin to the question I thought I was answering at the time.

In my first example, he doesn't really want the newest status_date itself, but rather the newest project status type. This would change the property substantially; you don't need to use a MAX() SQL construct at all; you just want the first record attached to this object when ordered by date descending:

class Project(models.Model):
    [...]

    @property
    def project_status(self):
        return self.status.order_by('-status_date')[0]

The use cases around this are still the same. If you will always get a project first and then want to know its current status, this is the right way to go about it. If you need to index projects by status, then you need to denormalize. This is still best done through signals, but instead of saving the date like I was doing in my example above, you probably want to save a description. The principle remains the same, though.

时光是把杀猪刀 2024-12-18 19:28:07

根据您的描述,我假设您实际上正在使用 ProjectStatus 作为 ManyToManyFieldthrough,并且您已经在存储有关与该模型关系的额外数据。如果额外数据项之一还不是设置该特定状态时的日期时间,我会将其添加到您的模型中。

然后,您可以按该日期时间降序对 ProjectStatus 进行排序,因此返回的第一个 ProjectStatus 将始终是最新的(当前)。

By your description, I'm assuming you're in fact using ProjectStatus as the through for your ManyToManyField, and that you're already storing extra data on the relationship with that model. If one of the items of extra data is not already the datetime when the that particular status was set, I would add that to your model.

You can then order ProjectStatus by that datetime, descending, so the first ProjectStatus returned will always be the most recent (current).

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