【问题标题】:Returning the current project status (i.e., most recent date on Django ManyToMany relationship)返回当前项目状态(即 Django ManyToMany 关系的最近日期)
【发布时间】:2023-04-08 07:53:01
【问题描述】:

架构描述

项目的状态会随着时间而改变。为了跟踪一段时间内的状态,我通过ProjectStatus 中间表在Project 模型和ProjectStatusType 模型之间创建了多对多关系。

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

用例

我希望能够返回处于给定状态的所有项目,例如所有open 项目。例如,当用户访问http://www.example.com/projects 时,我希望默认情况下仅将open 项目显示在表格中。

问题

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

【问题讨论】:

  • 完全不相关,但是您是否手动创建了图像,或者您是否有某种基于您的模型创建的自动化工具。似乎是这样,因为它与 Django 网站和管理员的颜色方案相匹配......如果是这样,我想使用该工具:)。
  • @jro:我在 OS X 上使用 OmngiGraffle Professional 使用从 Graffletopia.com 下载的 Django 绘图模板创建绘图。

标签: django database-design django-models database-schema


【解决方案1】:

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

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

【讨论】:

  • 我更新了架构图以表明我实际上使用ProjectStatus 作为throughManyToManyFieldProjectStatus 模型中关于该关系的唯一额外数据存储是 status_date 字段,用于反映最初设置状态的时间。
【解决方案2】:

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

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']

此策略记录在 here

如果您需要进行查找,那么您应该对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)

您可以阅读有关信号的更多信息here

======

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

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

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

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

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

【讨论】:

  • 是的,我想“按状态索引项目”。例如,我希望能够获得处于open 状态的所有项目或处于closed 状态的所有项目。基于该用例,我似乎需要非规范化。谢谢。
  • 是的。在Project 中添加当前状态列,并使用 post_save 信号写入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多