A Calendar Event Example

In this example we create a basic Calendar event, which store recurring events. The benefits of using a localized recurrence in this way are two fold. First, that you don’t have to store a separate entry for every time the event happens, only one localized recurrence describing how the event recurs. Second, the code for keeping track of the conversion between a user’s local time and UTC, even across daylight savings time boundaries is automatically handled by the recurrence updates.

We start by defining a model with a foreign key to LocalizedRecurrence.

from django.contrib.auth.models import User
from django.db import models

from localized_recurrence import LocalizedRecurrence

class RecurringCalendarEvent(models.Model):
    user = models.ForeignKey(User)
    event_name = models.CharField(max_length=120)
    event_description = models.TextField()
    recurrence = models.ForeignKey(LocalizedRecurrence)

    objects = RecurringCalendarEventManager()

To go along with the event model, we create a manager that can create the localized recurrence and event at the same time.

class RecurringCalendarEventManager(models.Manager):
    def create_event(self, name, description, user, timezone, offset, interval):
        recurrence = LocalizedRecurrence.objects.create(
        event = self.create(
        return event

Then, in a file views.py we can create two views. The first is a view that is intended to show a simple calendar but that first checks to see if there are any events that are due to be shown the user. It does this by filtering on the next_scheduled field of the associated LocalizedRecurrence objects.

from datetime import datetime

from django.shortcuts import redirect
from django.views.generic import TemplateView

class CalendarView(TemplateView):
    template_name = 'calendar/full_calendar.html'

    def get(self, request, *args, **kwargs):
        events_past_due = RecurringCalendarEvent.objects.filter(
        if events_past_due.count() > 0:
            return super(CalendarView, self).get(request, *args, **kwargs)

The second view (also assumed to be in the views.py file) is the view that displays any of the events that are past due. In this view, the get_context_data takes care of both passing the events to the template, but also updating the LocalizedRecurrence objects so that their next_scheduled fields are automatically set to the appropriate time in the future.

class CalendarNotification(TemplateView):
    template_name = 'calendar/event_notification.html'

    def get_context_data(self):
        context = super(CalendarNotification, self)
        events_past_due = RecurringCalendarEvent.objects.filter(
            id__in=[event.recurrence for event in events_past_due]
        context['events_past_due'] = events_past_due
        return context

Then all that’s left is presenting this information in an attractive manner.

In this usage of the LocalizedRecurrence objects, checking the recurrences depends on the user actually visiting a page to hit the code path. It would also be possible to check if the recurrences are past due in a separate task, like the celery-beat scheduler.