日历中重复“事件”:CPU与数据库的比较
我正在从零开始构建一个日历系统(因为我需要处理一种特殊的日历,除了公历之外),所以我需要一些逻辑方面的帮助。我正在用Django和Python编写这个应用。
我遇到的主要逻辑问题是,如何尽可能少地保存对象,同时又要聪明地处理这些对象,避免浪费CPU资源。我觉得多态性可能是解决这个问题的方法,但我不太确定该怎么表达。
我有两种基本的事件类型:重复事件和一次性事件。
重复事件会有订阅者,也就是那些会被通知事件变化的人。例如,如果一节课被取消或更改了地址或时间,订阅的人需要知道这个消息。有些事件会每天发生,直到永远,不会被编辑,"就这样发生"。问题是,如果我有一个对象来存储事件信息和它的重复规则,那么取消或修改这个系列中的一个事件就会搞得一团糟,我必须想办法处理这个问题,让订阅者知道变化,同时保持这个系列作为一个逻辑上的整体。
矛盾:如果我为每个正常事件生成独特的事件对象,直到永远(如果它无限重复),这就没有意义,因为它们都要存储相同的信息;然而,如果这个系列中的某个事件发生了变化,我几乎必须在数据库中创建一个不同的对象来表示取消。
有人能帮我理清这个逻辑吗?这真的让我很困惑,我现在都想不清楚了。我非常希望能得到一些建议,来解决这个问题,因为重复事件的逻辑也不是那么简单(比如每隔一天重复,或者每周一、三、五,或者每个月的第一个周一,或者每三个月,或者每年在这个日期,或者每周在这个日期,或者每月在这个日期,或者每周二上午9点和周四上午11点等等),我也想了解重复事件的最佳逻辑处理方式。
这是一个关于如何处理的想法:
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()
这似乎有点道理,但如上所述,这让我脑袋很痛,所以任何方法看起来都像是可行的。(还有另一个问题,如果有人想修改系列中所有剩余的事件,我该怎么办!?我想我可以改变'系列默认时间',然后为所有过去的实例生成异常实例,把它们设置回原来的时间,但啊啊啊啊!!!)
把问题简化成三个简单具体的问题,我们有:
4 个回答
我创建了一个事件系列模型,针对一个我完全不知道怎么表示的字段IHaveNoIdeaInTheWorldOnHowToRepresentThisField
,我的解决办法是使用pickle对象字段来保存一个重复规则(rrule
),这个规则来自dateutil
库。
这个话题可能会引发激烈的讨论,因为日期逻辑通常比看起来要复杂得多,每个人都会有自己处理事情的想法。
我可能会牺牲一些数据库空间,让模型尽量简单(比如不需要为一系列事件定义异常情况)。重复的条件可以是一些简单的术语,需要根据你的需求进行解析,或者——保持简单——只记录下一个事件发生的时间间隔。
从这些信息中,你可以生成“下一个”事件,它会复制重复的条件,然后根据实际需要生成未来的多个事件(可以设定一个最大时间范围来生成事件,但只有在有人查看相关时间段时才生成这些事件)。这些事件可以指向它的父事件,这样整个系列就能被识别(就像一个链表一样)。
模型应该有一个指示,表示某个单独的事件是否被取消。(事件仍然保留在数据库中,以便将来可以复制这个事件)。如果取消整个系列,则会删除事件列表。
我想专门讲讲第三个问题,关于假期的。
在几个报告数据库中,我发现定义一个表格很有用,我们可以叫它“年鉴”,这个表里每一行代表一个日期,日期范围可以设定在某个特定的时间段内。如果这个时间段跨越十年,这个表大约会有3652行数据。这个数量在今天看来算是比较小的。这个表的主键就是日期。
其他一些列可以记录这个日期是否是节假日、正常工作日或者周末。我知道,你可以用内置函数来计算周末的日期。但实际上,把这些信息作为数据存储起来会更方便,这样在连接数据时会更简单,也更一致。
然后你会有一个应用程序来填充这个年鉴。这个程序里包含了所有的日历规则,包括企业用来判断哪些天是节假日的规则。如果你的情况需要的话,你甚至可以加上某个日期属于哪个“财务月份”的列。之后,其他的应用程序,无论是输入程序还是提取程序,都会把年鉴当作普通数据来处理。
这可能看起来不够优化,因为它不是最小化的设计。但相信我,这种设计模式在很多情况下都很有用。具体怎么应用到你的情况,就得你自己去想了。
年鉴其实是数据仓库和星型模式设计原则的一部分。
如果你想在CPU内部做同样的事情,你可以有一个“年鉴”对象,里面有一些公共功能,比如Almanac.holiday(date)。