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…
But it does not show up on July 1…
My event has an end time in July…and a start time in June….
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…
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.
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…
But it does not show up on July 1…
My event has an end time in July…and a start time in June….
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…
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.