Повторение «событий» в календаре: CPU vs Database - PullRequest
7 голосов
/ 06 сентября 2011

Я строю систему календаря с нуля (требование, так как я работаю с особым типом календаря наряду с григорианским), и мне нужна помощь с логикой.Я пишу приложение на Django и Python.

По сути, логические проблемы, с которыми я сталкиваюсь, это как сохранить как можно меньше объектов, насколько это разумно, без использования вкладок циклов ЦП.Я чувствую, что полиморфизм был бы решением этой проблемы, но я не совсем уверен, как выразить это здесь.

У меня есть два основных подмножества событий: повторяющиеся и одноразовые.

Повторяющиеся события будут иметь подписчиков, людей, которые будут уведомлены об их изменениях.Если, например, класс отменен или перемещен на другой адрес или время, люди, которые подписались, должны знать об этом.Некоторые события просто происходят каждый день до конца времени, не будут редактироваться и «просто произойдут».Проблема в том, что если у меня есть один объект, который хранит информацию о событии и его повторяющуюся политику, то отмена или изменение одного события в серии действительно испортит ситуацию, и мне придется как-то это учитывать, сохраняяподписчики знают об изменениях и держат серию в единую логическую группу.

Парадокс: генерирование уникальных объектов событий для каждого нормального события в серии до конца времени (если оно повторяется бесконечно) не имеет смысла, если они все собираются хранить одну и ту же информацию;однако, если какое-либо изменение произойдет с одним событием в серии, у меня почти будет , чтобы создать другой объект в базе данных для представления отмены.

Может кто-нибудь помочь мне с логикой здесь?Это действительно искажает мой разум, и я не могу больше думать прямо.Мне бы очень хотелось получить информацию о том, как решить эту проблему, поскольку повторение событий не совсем легкая логическая вещь (повторение через день или каждые M / W / F, или 1-е число каждого месяца, иликаждые 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', а затем сгенерировать экземпляры аномалий для всех прошлых экземпляров, чтобы установить ихк первоначальному времени, но АХХХХХХ !!!)

Сводя его к трем простым конкретным вопросам, мы имеем:

  1. Как я могу провести серию повторяющихся событий, покаразрешить отмены и модификации отдельных событий и модификаций для остальной части серии в целом, сохраняя при этом как можно меньше объектов в базе данных, никогда не создавая объекты для отдельных событий заранее?
  2. Как я могу повторять события в высокой степени настраиваемым способом, не теряя рассудка, в том, что я могу позволить событиям повторяться числом способов , но опять же упростить задачу и сохранить как можно меньше объектоввозможно?
  3. Как я могу сделать все вышеперечисленное, учитывая переключение на каждую серию событийчтобы этого не случилось, если он выпадет в праздник ?

Ответы [ 4 ]

3 голосов
/ 06 сентября 2011

Это может стать жаркой дискуссией, так как логика дат обычно намного сложнее, чем кажется на первый взгляд, и у каждого будет своя собственная идея, как добиться успеха.

Я бы, вероятно, пожертвовал бы некоторым пространством в дБ, и модели были бы настолько глупыми, насколько это возможно (например, из-за отсутствия необходимости определять аномалии для ряда).Условием повторения могут быть либо простые термины, которые необходимо проанализировать (в зависимости от ваших требований), либо - KISS - просто интервал следующего события.

Из этого вы можете сгенерировать «следующее» событие, которое будет копировать условие повтора, и вы сгенерируете столько событий в будущем, сколько практически необходимо (определите некоторое максимальное временное окно в будущее, для которого нужно генерировать событияно генерировать их только тогда, когда кто-то на самом деле смотрит на рассматриваемое время).События могут иметь указатель на свое родительское событие, поэтому можно идентифицировать всю серию (точно так же, как связанный список).

Модель должна иметь индикатор того, отменено ли одно событие.(Событие остается в БД, чтобы иметь возможность скопировать событие в будущее).Отмена всей серии удаляет список событий.

РЕДАКТИРОВАТЬ: другие ответы упомянули пакет dateutil для построения и анализа интервалов, что на самом деле выглядит очень хорошо.

1 голос
/ 06 сентября 2011

Я хочу ответить только на вопрос 3 о праздниках.

В нескольких базах данных отчетов мне было удобно определять таблицу, назовем ее «Альманах», в которой по одной строке для каждой даты в определенном диапазоне. Если диапазон охватывает десять лет, таблица будет содержать около 3652 строк. Это мало по сегодняшним меркам. Первичным ключом является дата.

Некоторые другие столбцы - это, например, дата, выходной, обычный рабочий день или выходной. Я знаю, я знаю, вы могли бы вычислить материал на выходные, используя встроенную функцию. Но оказывается, что это удобно включать в данные. Это делает ваши объединения более простыми и похожими друг на друга.

Тогда у вас есть одна прикладная программа, которая заполняет Альманах. В него встроены все особенности календаря, включая корпоративные правила для определения того, какие дни являются выходными. Вы даже можете включить столбцы, к которым относится «финансовый месяц» к данной дате, если это относится к вашему случаю. Остальная часть приложения, как программы ввода, так и программы извлечения, обрабатывают Альманах как простые старые данные.

Это может показаться неоптимальным, потому что оно не минимально. Но поверьте мне, этот шаблон дизайна полезен в самых разных ситуациях. Вам решать, как это относится к вашему делу.

Альманах на самом деле является подмножеством принципов хранилищ данных и проектирования звездных схем.

если вы хотите сделать то же самое внутри ЦП, у вас может быть объект «Альманах» с общедоступными функциями, такими как Almanac.holiday (дата).

1 голос
/ 06 сентября 2011

Для модели серии событий, которую я создал, моим решением IHaveNoIdeaInTheWorldOnHowToRepresentThisField было использование поля маринованного объекта для сохранения правила повторения (rrule) из dateutil в моя модель серии событий.

0 голосов
/ 06 сентября 2011

Я столкнулся с теми же проблемами, что и вы, некоторое время назад. Однако первоначальное решение не содержало каких-либо аномалий или отмен, только повторяющиеся события. Способ, которым мы смоделировали набор повторяющихся событий, состоит в том, чтобы иметь некоторое поле, указывающее тип интервала (например, ежемесячно / еженедельно / ежедневно), а затем расстояния (например, каждый 2-й день, 2-я неделя и т. Д.), Начиная с данного начального дня , Этот простой способ повторения не охватывает слишком много сценариев, но было очень легко вычислить повторяющиеся даты. Возможны и другие способы повторения, например, что-то вроде cronjobs .

Чтобы сгенерировать повторения, мы создали табличную функцию, которая по некоторому идентификатору пользователя генерировала все повторения событий на лету примерно на 5 лет в будущем с использованием рекурсивного SQL (например, в Ваш подход, для набора повторений, должно быть сохранено только одно событие). Пока это работает очень хорошо, и к табличной функции можно обращаться так, как будто отдельные повторения действительно хранятся в базе данных. Это также может быть легко расширено, чтобы исключить любые отмененные события и заменить измененные события, основанные на датах, также на лету. Я не знаю, возможно ли это с вашей базой данных и вашим ORM.

...