0

I am trying to create a calendar with events showing under the date if and event has been created in the Event model along with a DateTimeField.

Here's my code: views.py

from django.shortcuts import render
import calendar

from .models import Event

def Cal(request, year, month):
    calendar.setfirstweekday(calendar.SUNDAY)
    prev_year = int(year)
    next_year = int(year)
    prev_month = int(month) - 1
    next_month = int(month) + 1
    if prev_month == 0:
        prev_year -= 1
        prev_month = 12
    if next_month == 13:
        next_year += 1
        next_month = 1
    month_cal = calendar.monthcalendar(int(year), int(month))
    events = Event.objects.filter(when__year=year, when__month=month)
    return render(request, "cal/calendar.html", {
                                                "month_cal": month_cal,
                                                "prev_month": prev_month,
                                                "next_month": next_month,
                                                "prev_year": prev_year,
                                                "next_year": next_year,
                                                "events": events,
                                            })

calendar.html

{% extends "base.html" %}

{% block body %}
<table border="1" cellspacing="0" cellpadding="10" width="40%" height="80%">
    <tr>
        <td>Sun</td>
        <td>Mon</td>
        <td>Tue</td>
        <td>Wed</td>
        <td>Thu</td>
        <td>Fri</td>
        <td>Sat</td>
    </tr>
    {% for week in month_cal %}
        <tr>
        {% for day in week %}
            <td>
                {% if day == 0 %}
                    -
                    {% else %}
                    {{ day }}
                    {% endif %}
            </td>
            {% endfor %}
        </tr>
    {% endfor %}
</table>


<a href="{% url 'calendar:calendar' prev_year prev_month %}">previous</a>
<a href="{% url 'calendar:calendar' next_year next_month %}">next</a>
{% endblock %}

I am successfully able to loop through all the events and loop through all the dates in the calendar. But, I want the events to be displayed inside the calendar under appropriate dates.

MiniGunnR
  • 5,590
  • 8
  • 42
  • 66

1 Answers1

1

I suggest adding a mapping of {day_of_month: events} in your context instead of a list of all events for the whole month. That way, when building your template, you don't need to iterate over all events for each day of the month.

Here's a sample implementation:

views.py

from collections import defaultdict

...

def Cal(request, year, month):

    ...

    events = Event.objects.filter(when__year=year, when__month=month)
    event_days = defaultdict(list)
    for event in events:
        event_days[event.when.day].append(event)
    return render(request, "cal/calendar.html", {
                                            "month_cal": month_cal,
                                            "prev_month": prev_month,
                                            "next_month": next_month,
                                            "prev_year": prev_year,
                                            "next_year": next_year,
                                            "event_days": event_days,
                                        })

Next, you'll need to include a dict lookup template filter in your project. (See linked question for the implementation.)

Now, as you're looping through your calendar, you can easily access the events by day:

calendar.html

...

{% for week in month_cal %}
    <tr>
    {% for day in week %}
        <td>
            {% if day == 0 %}
                -
            {% else %}
                {{ day }}
                {% for event in event_days|get_item:day %}
                    {# format the event here #}
                    {{ event.description }} 
                {% endfor %}
            {% endif %}
        </td>
        {% endfor %}
    </tr>
{% endfor %}

...
Community
  • 1
  • 1
keithb
  • 1,940
  • 16
  • 15
  • Thanks. I am trying to understand what this line does `event_days = defaultdict(list)`. Where does the `list` variable come from? – MiniGunnR Apr 18 '16 at 06:36
  • [`defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict) takes a factory function as a constructor. [`list`](https://docs.python.org/3/library/functions.html#func-list) is a builtin type. So `defaultdict(list)` will automate the creation of a list when calling `append()`. See http://stackoverflow.com/questions/5900578/how-does-collections-defaultdict-work for more. – keithb Apr 19 '16 at 13:22