重复"事件"在日历中:CPU与数据库

时间:2011-09-05 22:28:55

标签: python django database-design calendar logic

我正在从头开始构建一个日历系统(要求,因为我正在与Gregorian一起使用特殊类型的日历),我需要一些逻辑方面的帮助。我正在用Django和Python编写应用程序。

基本上,我遇到的逻辑问题是如何在不占用CPU周期选项卡的情况下尽可能巧妙地保留尽可能少的对象。我觉得多态性可以解决这个问题,但我不确定如何在这里表达它。

我有两个基本的事件子集,重复事件和一次性事件。

重复事件将有订阅者,人们会收到有关其更改的通知。例如,如果一个班级被取消或移动到不同的地址或时间,那么订阅的人需要知道这一点。有些事件每天都会发生,直到时间结束,不会被编辑,“只是发生”。问题是如果我有一个对象存储事件信息及其重复策略,那么取消或修改系列中的一个事件确实搞砸了,我将不得不以某种方式解释这个问题,让订阅者了解更改并将系列保持为逻辑组。

悖论:为一系列中的每个正常事件生成唯一的事件对象,直到时间结束(如果它无限重复),如果他们都要存储相同的信息,则没有意义;但是,如果系列中的单个事件发生任何变化,我几乎 在数据库中创建一个不同的对象来表示取消。

有人可以帮我解决这个问题吗?它真的扭曲了我的思绪,我不能再思考了。我真的很喜欢如何解决这个问题的一些意见,因为重复事件也不是最简单的逻辑事件(每隔一天重复一次,或每个M / W / F,或每个月的第一个M,或者每3个月,或者在这个日期每年一次,或者在这个日期每周一次,或者在这个日期每月一次,或者在星期二的上午9:00和星期四的上午11:00等,并且我会比如帮助理解重复事件的最佳逻辑路线。

以下是关于如何做到这一点的想法:

class EventSeries(models.Model):
    series_name = models.TextField()
    series_description = models.TextField()
    series_repeat_policy = models.IHaveNoIdeaInTheWorldOnHowToRepresentThisField()
    series_default_time = models.TimeField()
    series_start_date = models.DateField()
    series_end_date = models.DateField()
    location = models.ForeignKey('Location')

class EventSeriesAnomaly(models.Model):
    event_series = models.ForeignKey('EventSeries', related_name="exceptions")
    override_name = models.TextField()
    override_description = models.TextField()
    override_time = models.TimeField()
    override_location = models.ForeignKey('Location')
    event_date = models.DateField()

class EventSeriesCancellation(models.Model):
    event_series = models.ForeignKey('EventSeries', related_name="cancellations")
    event_date = models.TimeField()
    cancellation_explanation = models.TextField()

这似乎有点道理,但如上所述,这正在破坏我的大脑,所以任何事情似乎都会起作用。 (另一个问题和疑问,如果有人想要修改系列中的所有剩余事件,我该怎么做!?!?我想我可以更改'series_default_time'然后为所有过去的实例生成异常实例来设置它们到原来的时间,但是AHHHHHH !!!)

将其归结为三个简单,具体的问题,我们有:

  1. 我如何拥有一系列重复事件,但允许对整个系列的其余部分中的单个事件修改进行取消和修改,同时在数据库中存储的对象数量为绝对必要,不提前为个别事件生成对象?
  2. 如何以高度可自定义的方式重复事件,而不会失去理智,因为我可以允许事件在number of ways中重复,但又能让事情变得简单并尽可能少地存储对象?
  3. 如何才能完成上述所有操作,允许在每个事件系列中进行切换,以使其在holiday失效时不会发生?

4 个答案:

答案 0 :(得分:3)

这可能会成为一个激烈的讨论,因为日期逻辑 比起初看起来要困难得多,每个人都会有自己的想法如何让事情发生。

我可能会牺牲一些数据库空间并让模型尽可能愚蠢(例如,不必为系列定义异常)。重复条件可以是一些必须解析的简单术语(取决于您的要求)或 - KISS - 只是下一个事件发生的间隔。

由此您可以生成“下一个”事件,该事件将复制重复条件,并且您将在实际需要时生成尽可能多的事件(定义将来生成事件但生成事件的最新时间窗口)只有,当某人实际上看到有问题的时间间隔时)。事件可以有一个指向其父事件的指针,因此可以识别整个序列(就像链接列表一样)。

模型应该有一个指示器,是否取消单个事件。 (事件保留在数据库中,以便能够将事件复制到将来)。取消整个系列会删除事件列表。

编辑:other answers已经提到the dateutil package用于间隔构建和解析,这看起来非常好。

答案 1 :(得分:1)

对于我创建的事件系列模型,我对IHaveNoIdeaInTheWorldOnHowToRepresentThisField的解决方案是使用pickled object field在我的事件序列模型中保存来自dateutil的重复规则(rrule) 。

答案 2 :(得分:1)

我只想解决有关假期的问题3。

在几个报告数据库中,我发现定义一个表很方便,我们称之为“Almanac”,在一定范围内每个日期都有一行。如果范围跨越十年,则该表将包含大约3,652行。按今天的标准来看,这个数字很小。主键是日期。

其他一些列是日期是假日,正常工作日还是周末日。我知道,我知道,您可以使用内置函数计算周末的东西。但事实证明将这些东西作为数据包含在内是很方便的。它使您的连接更简单,更相似。

然后你有一个填充年历的应用程序。它具有内置的所有日历怪癖,包括用于确定哪些日子是假日的企业规则。您甚至可以包含给定日期所属的“会计月”的列,如果这与您的案例相关。应用程序的其余部分,包括入门程序和提取程序,都将Almanac视为普通旧数据。

这似乎不是最理想的,因为它并不是最小的。但请相信我,这种设计模式在各种情况下都很有用。由你决定它如何适用于你的情况。

Almanac实际上是数据仓库和星型模式设计原则的一部分。

如果你想在CPU内部做同样的事情,你可以拥有一个具有公共功能的“Almanac”对象,例如Almanac.holiday(date)。

答案 3 :(得分:0)

我遇到了与你前一段时间完全相同的问题。但是,初始解决方案不包含任何异常或取消,只是重复事件。我们建模一组重复事件的方式是让一些字段指示间隔类型(如月/周/每日),然后是从给定的开始日开始的距离(如每第2天,第2周等) 。这种简单的重复方式并不包含太多场景,但计算重复日期非常容易。其他重复方式也是可能的,例如cronjobs定义的方式。

为了生成重复,我们创建了一个表函数,给定一些用户标识使用递归SQL在运行中生成所有事件重复即时,直到未来5年(如此)在你的方法中,对于一组重复,只需要存储一个事件)。到目前为止,这种方法非常有效,并且可以查询表函数,就好像单个重复实际存储在数据库中一样。它也可以轻松扩展,以排除任何已取消的事件,并根据日期替换已更改的事件,也可以在运行中。我不知道你的数据库和ORM是否可行。