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
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( interval=interval, offset=time, timezone=timezone ) event = self.create( user=user, event_name=name, description=description, recurrence=recurrence ) 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
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( user=self.request.user, recurrence__next_scheduled__lte=datetime.utcnow() ) if events_past_due.count() > 0: redirect('calendar.event_notification') else: 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,
get_context_data takes care of both passing the events to the
template, but also updating the
LocalizedRecurrence objects so that
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( user=self.request.user, recurrence__next_scheduled__lte=datetime.utcnow() ) LocalizedRecurrence.objects.filter( id__in=[event.recurrence for event in events_past_due] ).update_schedule() 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.