How Do I Detect And Properly Display Events On Calendar That Overlaps Months in Python?

Question:

I used a tutorial I found online to create an event calendar in Python. I’ve tried to improve it to schedule events that may have a start and end time range that overlap months. Meaning it may start in June and end in July. I’ve got it partially figured out…I can display the events based on the start day being lte day in the Python HTMLCalendar module. I can’t figure out how to pick up the remaining day for July 1. June displays perfectly.

Here’s my code…

HTMLCALENDAR Utility..

class Calendar(HTMLCalendar):
    def __init__(self, year=None, month=None, dropdown=None):
        self.dropdown = dropdown
        self.year = year
        self.month = month
        super(Calendar, self).__init__()

# formats a day as a td
# filter events by day
def formatday(self, day, requests):
    requests_per_day = requests.filter(start_time__day__lte=day,start_time__month=self.month)
    d = ''
    for request in requests_per_day:
        d += f'<li> {request.get_html_url} </li>'

    if day != 0:
        return f"<td><span class='date'>{day}</span><ul> {d} </ul></td>"
    return '<td></td>'

# formats a week as a tr
def formatweek(self, theweek, requests):
    week = ''
    for d, weekday in theweek:
        week += self.formatday(d, requests)
    return f'<tr> {week} </tr>'

# formats a month as a table
# filter events by year and month
def formatmonth(self, withyear=True):
    # requests = VacationRequest.objects.filter(Q(vacation_calendar=self.dropdown,start_time__year=self.year,start_time__month=self.month) | Q(vacation_calendar=self.dropdown,start_time__year=self.year,end_time__month=self.month)).distinct()
    requests = VacationRequest.objects.filter(vacation_calendar=self.dropdown,start_time__year=self.year,start_time__month=self.month)
    cal = f'<table border="0" cellpadding="0" cellspacing="0" class="calendar">n'
    cal += f'{self.formatmonthname(self.year, self.month, withyear=withyear)}n'
    cal += f'{self.formatweekheader()}n'
    for week in self.monthdays2calendar(self.year, self.month):
        cal += f'{self.formatweek(week, requests)}n'
    cal += f'</table>n'
    cal += f'<h1 class="title107">Vacation Schedule For {self.formatmonthname(self.year, self.month, withyear=withyear)}</h1>n'
    return cal

My View…

class VacationRequestCalendarView(LoginRequiredMixin,generic.ListView):
    model = VacationRequest
    template_name = 'vacation_request_calendar_view.html'

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    dropdown = (self.request.GET.get("dropdown", None))
    d = get_date(self.request.GET.get('month', None))
    cal = Calendar(d.year, d.month, dropdown)
    cal.setfirstweekday(calendar.SUNDAY)
    html_cal = cal.formatmonth(withyear=True)
    vacation_calendar = VacationCalendar.objects.get(id=self.request.GET.get("dropdown", None))
    context['calendar'] = mark_safe(html_cal)
    context['dropdown'] = dropdown
    context['next_month'] = next_month(d)
    context['prev_month'] = prev_month(d)
    context['vacation_calendar'] = vacation_calendar
    return context

def get_object(self, queryset=None):
    return get_object_or_404(VacationCalendar, id=self.request.GET.get("dropdown"))

def get(self, request, *args, **kwargs):
    dropdown=self.request.GET.get("dropdown")
    if dropdown is not None:
        if VacationCalendar.objects.filter(id=dropdown,team_members=self.request.user):
            self.object_list = self.get_queryset()
            context = self.get_context_data(object=self.object_list)
            return self.render_to_response(context)
        else:
            raise Http404
    else:
        messages.add_message(self.request, messages.INFO, 'Vacation Calendar is required.')
        return HttpResponseRedirect(reverse('VacationRequests:vacation_request_by_calendar_name'))

def get_date(req_month):
    if req_month:
        year, month = (int(x) for x in req_month.split('-'))
        return date(year, month, day=1)
    return datetime.today()

def prev_month(d):
    first = d.replace(day=1)
    prev_month = first - timedelta(days=1)
    month = 'month=' + str(prev_month.year) + '-' + str(prev_month.month)
    return month

def next_month(d):
    days_in_month = calendar.monthrange(d.year, d.month)[1]
    last = d.replace(day=days_in_month)
    next_month = last + timedelta(days=1)
    month = 'month=' + str(next_month.year) + '-' + str(next_month.month)
    return month

This displays my event for the month of June as I would hope…

enter image description here

But it does not show up on July 1…

enter image description here

My event has an end time in July…and a start time in June….

enter image description here

How can I get this event to show up on July 1 as well?

My latest attempt at this is close…..

events = VacationRequest.objects.filter(Q(vacation_calendar=dropdown,start_time__year = d.year,start_time__month = d.month)
        | Q(vacation_calendar=dropdown,end_time__month = d.month )).distinct().order_by('start_time')

Still trying to work it out…

Asked By: Steve Smith

||

Answers:

requests = VacationRequest.objects.filter(Q(vacation_calendar=self.dropdown,start_time__year=self.year,start_time__month=self.month)
        | Q(vacation_calendar=self.dropdown,start_time__year=self.year,end_time__month=self.month)).distinct()

Seemed to do the trick.

Answered By: Steve Smith