diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index 293b62ba8f886a0689d79121421de7e346bb9473..0f9c5f9e409b53f15bab8b1e4c4674e4076ab88b 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -1,13 +1,15 @@ from __future__ import annotations -from datetime import date, datetime, timedelta +from datetime import date, datetime, timedelta, time from typing import Dict, Optional, Tuple, Union from django.core import validators from django.core.exceptions import ValidationError from django.db import models -from django.db.models import F, Q +from django.db.models import F, Max, Min, Q +from django.db.models.functions import Coalesce from django.http.request import QueryDict +from django.utils.decorators import classproperty from django.utils.translation import ugettext_lazy as _ from calendarweek.django import CalendarWeek, i18n_day_names_lazy, i18n_day_abbrs_lazy @@ -244,6 +246,30 @@ class TimePeriod(models.Model): return wanted_week[self.weekday] + @classproperty + def period_min(cls) -> int: + return cls.objects.aggregate(period__min=Coalesce(Min("period"), 1)).get("period__min") + + @classproperty + def period_max(cls) -> int: + return cls.objects.aggregate(period__max=Coalesce(Max("period"), 7)).get("period__max") + + @classproperty + def time_min(cls) -> Optional[time]: + return cls.objects.aggregate(Min("time_start")).get("time_start__min") + + @classproperty + def time_max(cls) -> Optional[time]: + return cls.objects.aggregate(Max("time_start")).get("time_start__max") + + @classproperty + def weekday_min(cls) -> int: + return cls.objects.aggregate(weekday__min=Coalesce(Min("weekday"), 0)).get("weekday__min") + + @classproperty + def weekday_max(cls) -> int: + return cls.objects.aggregate(weekday__max=Coalesce(Max("weekday"), 6)).get("weekday__max") + class Meta: unique_together = [["weekday", "period"]] ordering = ["weekday", "period"] diff --git a/aleksis/apps/chronos/util/min_max.py b/aleksis/apps/chronos/util/min_max.py deleted file mode 100644 index 4d5dd421443f36b3b2f01ce0a2ef74b6504a0b5e..0000000000000000000000000000000000000000 --- a/aleksis/apps/chronos/util/min_max.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.db.models import Min, Max - -from aleksis.apps.chronos.models import TimePeriod - -# Determine overall first and last day and period -min_max = TimePeriod.objects.aggregate( - Min("period"), Max("period"), Min("weekday"), Max("weekday"), Min("time_start"), Max("time_end") -) - -period_min = min_max.get("period__min", 1) -period_max = min_max.get("period__max", 7) - -time_min = min_max.get("time_start__min", None) -time_max = min_max.get("time_end__max", None) - -weekday_min_ = min_max.get("weekday__min", 0) -weekday_max = min_max.get("weekday__max", 6) - - diff --git a/aleksis/apps/chronos/util/prev_next.py b/aleksis/apps/chronos/util/prev_next.py index c0a844dc40e728a17c98e6289def5bd69c1dd9b9..4f954c3082eb69e5c18afb12896c975ed07135b0 100644 --- a/aleksis/apps/chronos/util/prev_next.py +++ b/aleksis/apps/chronos/util/prev_next.py @@ -5,7 +5,7 @@ from calendarweek import CalendarWeek from django.urls import reverse from django.utils import timezone -from aleksis.apps.chronos.util.min_max import weekday_min_, weekday_max, time_max +from ..models import TimePeriod def get_next_relevant_day(day: Optional[date] = None, time: Optional[time] = None, prev: bool = False) -> date: @@ -15,23 +15,23 @@ def get_next_relevant_day(day: Optional[date] = None, time: Optional[time] = Non day = timezone.now().date() if time is not None and not prev: - if time > time_max: + if time > TimePeriod.time_max: day += timedelta(days=1) cw = CalendarWeek.from_date(day) - if day.weekday() > weekday_max: + if day.weekday() > TimePeriod.weekday_max: if prev: - day = cw[weekday_max] + day = cw[TimePeriod.weekday_max] else: cw += 1 - day = cw[weekday_min_] - elif day.weekday() < weekday_min_: + day = cw[TimePeriod.weekday_min] + elif day.weekday() < TimePeriod.weekday_min: if prev: cw -= 1 - day = cw[weekday_max] + day = cw[TimePeriod.weekday_max] else: - day = cw[weekday_min_] + day = cw[TimePeriod.weekday_min] return day diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py index 90cac9127e56297b181583de6d8b0572024b59b6..66ddde4a514ac2019b55dd4855b7886554a22356 100644 --- a/aleksis/apps/chronos/views.py +++ b/aleksis/apps/chronos/views.py @@ -18,12 +18,6 @@ from .forms import LessonSubstitutionForm from .models import LessonPeriod, LessonSubstitution, TimePeriod, Room from .tables import LessonsTable from .util.js import date_unix -from .util.min_max import ( - period_min, - period_max, - weekday_min_, - weekday_max -) from .util.prev_next import get_next_relevant_day, get_prev_next_by_day from .util.weeks import CalendarWeek, get_weeks_for_year from aleksis.core.util.core_helpers import has_person @@ -158,13 +152,13 @@ def timetable( ] = [lesson_period] # Fill in empty lessons - for period_num in range(period_min, period_max + 1): + for period_num in range(TimePeriod.period_min, TimePeriod.period_max + 1): # Fill in empty weekdays if period_num not in per_period.keys(): per_period[period_num] = {} # Fill in empty lessons on this workday - for weekday_num in range(weekday_min_, weekday_max + 1): + for weekday_num in range(TimePeriod.weekday_min, TimePeriod.weekday_max + 1): if weekday_num not in per_period[period_num].keys(): per_period[period_num][weekday_num] = [] @@ -174,10 +168,10 @@ def timetable( context["lesson_periods"] = OrderedDict(sorted(per_period.items())) context["periods"] = TimePeriod.get_times_dict() context["weekdays"] = dict( - TimePeriod.WEEKDAY_CHOICES[weekday_min_ : weekday_max + 1] + TimePeriod.WEEKDAY_CHOICES[TimePeriod.weekday_min : TimePeriod.weekday_max + 1] ) context["weekdays_short"] = dict( - TimePeriod.WEEKDAY_CHOICES_SHORT[weekday_min_ : weekday_max + 1] + TimePeriod.WEEKDAY_CHOICES_SHORT[TimePeriod.weekday_min : TimePeriod.weekday_max + 1] ) context["weeks"] = get_weeks_for_year(year=wanted_week.year) context["week"] = wanted_week