Как использовать HTMLCalendar
Я использую Django, и я использую модуль HTMLCalendar для печати календаря на странице. В настоящее время приведенный ниже код работает нормально, но когда дата между 'from date' и 'to date' больше 2 дней, я хочу выразить это в одной строке вместо того, чтобы добавлять событие к каждой дате, принадлежащей периоду. Сколько бы я не искал, я не смог найти ни одного поста с подобными трудностями, и я не могу решить их самостоятельно уже несколько дней. Помогите!
[models.py]
class Leave(models.Model):
title = models.CharField(max_length=50, blank=True, null=True)
from_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
memo = models.TextField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
is_deleted = models.BooleanField(default=False)
create_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
@property
def get_html_url(self):
url = reverse('leave:leave_edit', args=(self.id,))
return f'<div class="event-title" colspan="{self.end_date - self.from_date}"><a href="{url}" style="color:black;"> {self.title} </a></div>'
[forms.py]
class LeaveForm(ModelForm):
class Meta:
model = Leave
# datetime-local is a HTML5 input type, format to make date time show on fields
widgets = {
'from_date': DateInput(attrs={'type': 'datetime', 'class': 'datepicker', 'autocomplete': 'off'}, format='%Y-%m-%d'),
'end_date': DateInput(attrs={'type': 'datetime', 'class': 'datepicker', 'autocomplete': 'off'}, format='%Y-%m-%d'),
'user': Select(attrs={"disabled": 'disabled'}),
}
fields = ['title', 'from_date', 'end_date', 'memo', 'user']
def __init__(self, request, *args, **kwargs):
super(LeaveForm, self).__init__(*args, **kwargs)
# input_formats to parse HTML5 datetime-local input to datetime field
self.fields['from_date'].input_formats = ('%Y-%m-%d',)
self.fields['end_date'].input_formats = ('%Y-%m-%d',)
self.fields['user'].empty_label = request.user.username
[utils.py]
class Calendar(HTMLCalendar):
def __init__(self, year=None, month=None, user=None):
self.year = year
self.month = month
self.user = user
super(Calendar, self).__init__()
# formats a day as a td
# filter events by day
def formatday(self, day, events, next_visit):
events_per_day = events.filter(user=self.user).annotate(end_date_month=ExtractMonth('end_date'))\
.filter(Q(from_date__day=day, end_date__isnull=True) |
Q(from_date__day__lte=day, end_date__day__gte=day) |
(Q(from_date__day__lte=day, from_date__year=self.year, from_date__month=self.month) &
~Q(from_date__month=F('end_date_month'))) |
(Q(end_date__day__gte=day, end_date__year=self.year, end_date__month=self.month) &
~Q(from_date__month=F('end_date_month'))))
next_visit_per_day = next_visit.filter(next_visit__day=day, next_visit__year=self.year, next_visit__month=self.month, assignment__curr_crc=self.user.first_name)
d = ''
for event in events_per_day:
d += f'{event.get_html_url}'
for next_visit in next_visit_per_day:
d += f'{next_visit.get_html_url}'
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, events, next_visit):
week = ''
for d, weekday in theweek:
week += self.formatday(d, events, next_visit)
return f'<tr> {week} </tr>'
# formats a month as a table
# filter events by year and month
def formatmonth(self, withyear=True):
events = Leave.objects.filter(is_deleted=False)\
.filter(Q(from_date__year=self.year, from_date__month=self.month) |
Q(end_date__year=self.year, end_date__month=self.month))
next_visit = Feedback.objects.filter(assignment__is_deleted=0, next_visit__isnull=False)
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, events, next_visit)}\n'
return cal
[views.py]
class CalendarView(generic.ListView):
model = Leave
template_name = 'pages/leave/leave.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# use today's date for the calendar
d = get_date(self.request.GET.get('month', None))
context['prev_month'] = prev_month(d)
context['next_month'] = next_month(d)
first_name = self.request.user
# Instantiate our calendar class with today's year and date
cal = Calendar(d.year, d.month, first_name)
cal.setfirstweekday(6)
# Call the formatmonth method, which returns our calendar as a table
html_cal = cal.formatmonth(withyear=True)
context['calendar'] = mark_safe(html_cal)
context['leave'] = Leave.objects.filter(is_deleted=0)
return context
def get_date(req_day):
if req_day:
year, month = (int(x) for x in req_day.split('-'))
return datetime.date(year, month, day=1)
return datetime.datetime.today()
def prev_month(d):
first = d.replace(day=1)
prev_month = first - datetime.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 + datetime.timedelta(days=1)
month = 'month=' + str(next_month.year) + '-' + str(next_month.month)
return month
def leave(request, leave_id=None):
instance = Leave()
if leave_id:
instance = get_object_or_404(Leave, pk=leave_id)
else:
instance = Leave()
instance
form = LeaveForm(request, request.POST or None, instance=instance)
if request.POST and form.is_valid():
form = form.save(commit=False)
form.user = request.user
form.save()
return HttpResponseRedirect(reverse('leave:calendar'))
return render(request, 'pages/leave/leave_add.html', {'form': form})
@login_required()
def leave_delete(request, leave_id):
leave = Leave.objects.get(pk=leave_id)
leave.is_deleted = True
leave.save()
return HttpResponseRedirect(f'/leave/calendar/')