Issue
I’m using a tutorial I found online…and it’s mostly working…I’m stuck trying to loop through a list of events and display them each day. If I have an event that starts on June 1st and ends on June 5th, I want to be able to list the event on June 2nd and the events on June 3rd and June 4th. thinking about. Starts June 1st and ends June 5th. I’ve tried several different filters with GTE and LTE, but it doesn’t seem to work.
This is my calendar 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__()
# format day as td
# Filter events by day
def formatday(self, day, event):
events_per_day = events.filter(start_time__day__lte=day, end_time__day__gte=day)
d = ''
Events for events_per_day:
d += f'{event.get_html_url} '
If days != 0:
return f"{day} {d}
"
returns ' '
# Format week as tr
def formatweek(self, theweek, events):
week = ''
For d, the day of the week:
week += self.formatday(d, event)
returns f' {week} '
# format months as a table
# Filter events by year and month
def formatmonth(self, withyear=True):
events = VacationRequest.objects.filter(vacation_calendar=self.dropdown,start_time__year=self.year,start_time__month=self.month).order_by('start_time')
cal = f'\n'
cal += f'{self.formatmonthname(self.year, self.month, withyear=withyear)}\n'
cal += f'{self.formatweekheader()}\n'
Week of self.monthdays2calendar(self.year, self.month) :
cal += f'{self.formatweek(week, event)}\n'
cal += f'
\n'
cal += f' Vacation schedule for {self.formatmonthname(self.year, self.month, withyear=withyear)}
\n'
Return value
Here’s my view…
class VacationRequestCalendarView(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))
Vacation_calendar_requests = VacationRequest.objects.filter(start_time__year = d.year,start_time__month = d.month)
context['calendar'] = mark_safe(html_cal)
context['dropdown'] = dropdown
context['next_month'] = next_month(d)
context['prev_month'] = prev_month(d)
context['vacation_calendar_requests'] = Vacation_calendar_requests
context['vacation_calendar'] = vacation_calendar
return the context
def get_object (self, queryset=None):
return get_object_or_404(VacationCalendar, id=self.request.GET.get("Dropdown"))
Default get_date(req_month):
For req_month:
year, month = (int(x) of x in req_month.split('-'))
Return date (date = 1)
returns datetime.today()
def prev_month(d):
first = d.replace(day = 1)
prev_month = first - timedelta(days=1)
month = 'month=' + str(previous month.year) + '-' + str(previous month.month)
return month
Default next_month(d):
days_in_month = calendar.monthrange(d.year, d.month)[1]
last = d.replace (day = number of days in month)
next_month = last + timedelta(day=1)
month = 'month=' + str(next month.year) + '-' + str(next month.month)
return month
And here is my Django template logic for him…
{% ifvacation_calendar_requests %}
Requests for {% Vacation_calendar_requests %}
{% ifchanged request.start_time|date:"M d, Y" %}
{{ request.start_time|date:"M d, Y" }}
{% endifchanged %}
{% end for ichanged %}
{% other than that %}
No vacation plans
{% endif %}
The code above will properly display events that span multiple days on the calendar… this is due to the formatday function. I can see that the events by day are filtered correctly… I am not sure how to do the same when trying to output the events by day using template logic.
I see that the template loop only finds 2 events…that’s how I do it…but how can I loop by day instead of just the range to find the events? Uka (start time and end time?)
Add…
I found an example online how to do what I’m trying to do.. but I don’t know how to incorporate it into the code above… the example I found is…
from datetime import timedelta, date
Default date range (date 1, date 2):
for n in range(int ((date2 - date1).days)+1):
yield date1 + timedelta(n)
start_dt = date(2015, 12, 20)
end_dt = date (January 11, 2016)
For date range dt (start_dt, end_dt):
print(dt.strftime("%Y-%m-%d"))
And it’s from https://www.w3resource.com/python-exercises/date-time-exercise/python-date-time-exercise-50.php
But I don’t know how to include it…
Update…
I got a little closer by updating the Calendar utility to add the following code for the month format.
for self.monthdays2calendar(self.year, self.month):
For events:
# cal += f'{self.formatmonthname(self.year, self.month)}\n'
cal += f'{self.formatweek(week, event)}\n'
Return value
I’m almost done… except I’m printing some extra digits from the calendar format… I’m trying to print the month, day and year in the proper format.
Solution
I would calculate the duration (number of days), and then use that duration as the number of times to loop. Then to get the date for each day of the duration, I would use a counter variable (enumerator maybe) and add it to the date. For example when the counter is 2, then I would add 2 days to the start date to get the current date in the loop.
Hopefully this would give you an idea.
Using your example, add this to your view:
from datetime import timedelta, date
# Add this function outside the View, just like you did with the other ones
def daterange(date1, date2):
for n in range(int ((date2 - date1).days)+1):
yield date1 + timedelta(n)
def get_context_data(self, **kwargs):
## other code here ##
vacation_calendar_requests = VacationRequest.objects.filter(start_time__year = d.year,start_time__month = d.month)
# this will add a new field, "dates", to each event
for request in vacation_calendar_requests:
start_date = request.start_time
end_date = request.end_time
start_dt = date(start_date.year,start_date.month,start_date.day) # not sure if this is how you get your event start date
end_dt = date(end_date.year,end_date.month,end_date.day) # not sure if this is how you get your event end date
request.dates = [date for date in daterange(start_dt, end_dt)]
## rest of code here ##
Then in your template, add this nested loop to show the dates for each event:
{% for date in request.dates %}
{{ request.vacation_request_name }}
{{ date }} /* format the date accordingly */
{% endfor %}
Answered By – Kachinga
Answer Checked By – Candace Johnson (Easybugfix Volunteer)