##### Here is the template tag code. It goes in a file named
# "event_tags.py" in a subdirectory of your app called "templatetags".
#####
from calendar import HTMLCalendar
from django import template
from datetime import date
from itertools import groupby
from django.utils.html import conditional_escape as esc
register = template.Library()
def do_event_calendar(parser, token):
"""
The template tag's syntax is {% event_calendar year month event_list %}
"""
try:
tag_name, year, month, event_list = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires three arguments" % token.contents.split()[0]
return EventCalendarNode(year, month, event_list)
class EventCalendarNode(template.Node):
"""
Process a particular node in the template. Fail silently.
"""
def __init__(self, year, month, event_list):
try:
self.year = template.Variable(year)
self.month = template.Variable(month)
self.event_list = template.Variable(event_list)
except ValueError:
raise template.TemplateSyntaxError
def render(self, context):
try:
# Get the variables from the context so the method is thread-safe.
my_event_list = self.event_list.resolve(context)
my_year = self.year.resolve(context)
my_month = self.month.resolve(context)
cal = EventCalendar(my_event_list)
return cal.formatmonth(int(my_year), int(my_month))
except ValueError:
return
except template.VariableDoesNotExist:
return
class EventCalendar(HTMLCalendar):
"""
Overload Python's calendar.HTMLCalendar to add the appropriate events to
each day's table cell.
"""
def __init__(self, events):
super(EventCalendar, self).__init__()
self.events = self.group_by_day(events)
def formatday(self, day, weekday):
if day != 0:
cssclass = self.cssclasses[weekday]
if date.today() == date(self.year, self.month, day):
cssclass += ' today'
if day in self.events:
cssclass += ' filled'
body = ['
')
return self.day_cell(cssclass, '%d %s' % (day, ''.join(body)))
return self.day_cell(cssclass, '%d' % (day))
return self.day_cell('noday', ' ')
def formatmonth(self, year, month):
self.year, self.month = year, month
return super(EventCalendar, self).formatmonth(year, month)
def group_by_day(self, events):
field = lambda event: event.date_and_time.day
return dict(
[(day, list(items)) for day, items in groupby(events, field)]
)
def day_cell(self, cssclass, body):
return '%s | ' % (cssclass, body)
# Register the template tag so it is available to templates
register.tag("event_calendar", do_event_calendar)
##### Here's code for the view to look up the event objects for to put in
# the context for the template. It goes in your app's views.py file (or
# wherever you put your views).
#####
def named_month(month_number):
"""
Return the name of the month, given the number.
"""
return date(1900, month_number, 1).strftime("%B")
def this_month(request):
"""
Show calendar of events this month.
"""
today = datetime.now()
return calendar(request, today.year, today.month)
def calendar(request, year, month, series_id=None):
"""
Show calendar of events for a given month of a given year.
``series_id``
The event series to show. None shows all event series.
"""
my_year = int(year)
my_month = int(month)
my_calendar_from_month = datetime(my_year, my_month, 1)
my_calendar_to_month = datetime(my_year, my_month, monthrange(my_year, my_month)[1])
my_events = Event.objects.filter(date_and_time__gte=my_calendar_from_month).filter(date_and_time__lte=my_calendar_to_month)
if series_id:
my_events = my_events.filter(series=series_id)
# Calculate values for the calendar controls. 1-indexed (Jan = 1)
my_previous_year = my_year
my_previous_month = my_month - 1
if my_previous_month == 0:
my_previous_year = my_year - 1
my_previous_month = 12
my_next_year = my_year
my_next_month = my_month + 1
if my_next_month == 13:
my_next_year = my_year + 1
my_next_month = 1
my_year_after_this = my_year + 1
my_year_before_this = my_year - 1
return render_to_response("cal_template.html", { 'events_list': my_events,
'month': my_month,
'month_name': named_month(my_month),
'year': my_year,
'previous_month': my_previous_month,
'previous_month_name': named_month(my_previous_month),
'previous_year': my_previous_year,
'next_month': my_next_month,
'next_month_name': named_month(my_next_month),
'next_year': my_next_year,
'year_before_this': my_year_before_this,
'year_after_this': my_year_after_this,
}, context_instance=RequestContext(request))
##### Here is the code to load and use the template tag in a template.
{% load event_tags %}
{% event_calendar year month event_list %}