Examples¶
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(
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
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(
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,
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(
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.