From df2c5b5a0b12c818073e4376eeacaceef355c2e8 Mon Sep 17 00:00:00 2001
From: Tom Teichler <tom.teichler@teckids.org>
Date: Sun, 3 May 2020 16:10:33 +0200
Subject: [PATCH] [Reformat] black

---
 aleksis/apps/chronos/admin.py                 |   4 +-
 aleksis/apps/chronos/filters.py               |   2 +-
 aleksis/apps/chronos/forms.py                 |   4 +-
 aleksis/apps/chronos/managers.py              |  68 +-
 aleksis/apps/chronos/menus.py                 |  20 +-
 .../migrations/0005_remove_school_related.py  |  84 +--
 .../chronos/migrations/0006_extended_data.py  |  10 +-
 .../0007_advanced_models_from_untis.py        | 591 +++++++++++++-----
 .../chronos/migrations/0008_break_period.py   |  53 +-
 .../chronos/migrations/0009_extended_data.py  |  42 +-
 .../migrations/0010_absence_reason_name.py    |  32 +-
 .../0011_absence_for_groups_and_rooms.py      |  43 +-
 .../0012_event_remove_absence_reason.py       |   7 +-
 .../migrations/0013_event_title_optional.py   |  10 +-
 .../chronos/migrations/0014_extra_lesson.py   |  91 ++-
 .../0015_rename_abbrev_to_short_name.py       |   9 +-
 .../migrations/0016_add_globalpermissions.py  |  29 +-
 aleksis/apps/chronos/model_extensions.py      |   6 +-
 aleksis/apps/chronos/models.py                | 359 ++++++++---
 aleksis/apps/chronos/preferences.py           |   8 +-
 aleksis/apps/chronos/rules.py                 |  17 +-
 aleksis/apps/chronos/tables.py                |  16 +-
 aleksis/apps/chronos/templatetags/common.py   |   7 +-
 .../apps/chronos/templatetags/week_helpers.py |   6 +-
 aleksis/apps/chronos/urls.py                  |  44 +-
 aleksis/apps/chronos/util/build.py            |  16 +-
 aleksis/apps/chronos/views.py                 |  43 +-
 27 files changed, 1145 insertions(+), 476 deletions(-)

diff --git a/aleksis/apps/chronos/admin.py b/aleksis/apps/chronos/admin.py
index 56878a6c..8c99c4b5 100644
--- a/aleksis/apps/chronos/admin.py
+++ b/aleksis/apps/chronos/admin.py
@@ -1,4 +1,4 @@
-#noqa
+# noqa
 
 from django.contrib import admin
 from django.utils.html import format_html
@@ -153,7 +153,7 @@ admin.site.register(Room, RoomAdmin)
 
 class SubjectAdmin(admin.ModelAdmin):
     def _colour(self, obj):
-        return colour_badge(obj.colour_fg, obj.colour_bg, obj.short_name, )
+        return colour_badge(obj.colour_fg, obj.colour_bg, obj.short_name,)
 
     list_display = ("short_name", "name", "_colour")
     list_display_links = ("short_name", "name")
diff --git a/aleksis/apps/chronos/filters.py b/aleksis/apps/chronos/filters.py
index 8df8771d..dead4fc6 100644
--- a/aleksis/apps/chronos/filters.py
+++ b/aleksis/apps/chronos/filters.py
@@ -12,5 +12,5 @@ class HintForm(Form):
 class HintFilter(django_filters.FilterSet):
     class Meta:
         model = Hint
-        fields = ['from_date', "to_date", "classes", "teachers"]
+        fields = ["from_date", "to_date", "classes", "teachers"]
         form = HintForm
diff --git a/aleksis/apps/chronos/forms.py b/aleksis/apps/chronos/forms.py
index 685f67f7..1c56e201 100644
--- a/aleksis/apps/chronos/forms.py
+++ b/aleksis/apps/chronos/forms.py
@@ -22,4 +22,6 @@ class LessonSubstitutionForm(forms.ModelForm):
         }
 
 
-AnnouncementForm.add_node_to_layout(Fieldset(_("Options for timetables"), "show_in_timetables"))
+AnnouncementForm.add_node_to_layout(
+    Fieldset(_("Options for timetables"), "show_in_timetables")
+)
diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index 52ae31a3..2f32a3e4 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -93,8 +93,10 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
         """ Filter for all lessons within a calendar week. """
 
         return self.within_dates(
-            wanted_week[0] + timedelta(days=1) * (F(self._period_path + "period__weekday") - 1),
-            wanted_week[0] + timedelta(days=1) * (F(self._period_path + "period__weekday") - 1),
+            wanted_week[0]
+            + timedelta(days=1) * (F(self._period_path + "period__weekday") - 1),
+            wanted_week[0]
+            + timedelta(days=1) * (F(self._period_path + "period__weekday") - 1),
         ).annotate_week(wanted_week)
 
     def on_day(self, day: date):
@@ -129,7 +131,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
 
         return self.filter(
             Q(**{self._period_path + "lesson__groups__members": person})
-            | Q(**{self._period_path + "lesson__groups__parent_groups__members": person})
+            | Q(
+                **{self._period_path + "lesson__groups__parent_groups__members": person}
+            )
         )
 
     def filter_group(self, group: Union[Group, int]):
@@ -151,7 +155,12 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
         """ Filter for all lessons given by a certain teacher. """
 
         qs1 = self.filter(**{self._period_path + "lesson__teachers": teacher})
-        qs2 = self.filter(**{self._subst_path + "teachers": teacher, self._subst_path + "week": F("_week"), })
+        qs2 = self.filter(
+            **{
+                self._subst_path + "teachers": teacher,
+                self._subst_path + "week": F("_week"),
+            }
+        )
 
         return qs1.union(qs2)
 
@@ -159,7 +168,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
         """ Filter for all lessons taking part in a certain room. """
 
         qs1 = self.filter(**{self._period_path + "room": room})
-        qs2 = self.filter(**{self._subst_path + "room": room, self._subst_path + "week": F("_week"),})
+        qs2 = self.filter(
+            **{self._subst_path + "room": room, self._subst_path + "week": F("_week"),}
+        )
 
         return qs1.union(qs2)
 
@@ -184,7 +195,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
 
         return per_period
 
-    def filter_from_type(self, type_: TimetableType, pk: int) -> Optional[models.QuerySet]:
+    def filter_from_type(
+        self, type_: TimetableType, pk: int
+    ) -> Optional[models.QuerySet]:
         """Filter lesson data for a group, teacher or room by provided type."""
 
         if type_ == TimetableType.GROUP:
@@ -215,7 +228,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
             # If no student or teacher
             return None
 
-    def daily_lessons_for_person(self, person: Person, wanted_day: date) -> Optional[models.QuerySet]:
+    def daily_lessons_for_person(
+        self, person: Person, wanted_day: date
+    ) -> Optional[models.QuerySet]:
         """Filter lesson data on a day by a person."""
 
         if person.timetable_type is None:
@@ -225,7 +240,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
 
         return lesson_periods
 
-    def next(self, reference: "LessonPeriod", offset: Optional[int] = 1) -> "LessonPeriod":
+    def next(
+        self, reference: "LessonPeriod", offset: Optional[int] = 1
+    ) -> "LessonPeriod":
         """ Get another lesson in an ordered set of lessons.
 
         By default, it returns the next lesson in the set. By passing the offset argument,
@@ -260,7 +277,7 @@ class LessonSubstitutionQuerySet(LessonDataQuerySet):
 
     def affected_lessons(self):
         """ Return all lessons which are affected by selected substitutions """
-        from .models import Lesson # noaq
+        from .models import Lesson  # noaq
 
         return Lesson.objects.filter(lesson_periods__substitutions__in=self)
 
@@ -307,8 +324,7 @@ class DateRangeQuerySet(models.QuerySet):
         now = when or datetime.now()
 
         return self.on_day(now.date()).filter(
-            period_from__time_start__lte=now.time(),
-            period_to__time_end__gte=now.time()
+            period_from__time_start__lte=now.time(), period_to__time_end__gte=now.time()
         )
 
 
@@ -316,17 +332,24 @@ class AbsenceQuerySet(DateRangeQuerySet):
     """QuerySet with custom query methods for absences."""
 
     def absent_teachers(self):
-        return Person.objects.filter(absences__in=self).annotate(absences_count=Count("absences"))
+        return Person.objects.filter(absences__in=self).annotate(
+            absences_count=Count("absences")
+        )
 
     def absent_groups(self):
-        return Group.objects.filter(absences__in=self).annotate(absences_count=Count("absences"))
+        return Group.objects.filter(absences__in=self).annotate(
+            absences_count=Count("absences")
+        )
 
     def absent_rooms(self):
-        return Person.objects.filter(absences__in=self).annotate(absences_count=Count("absences"))
+        return Person.objects.filter(absences__in=self).annotate(
+            absences_count=Count("absences")
+        )
 
 
 class HolidayQuerySet(DateRangeQuerySet):
     """QuerySet with custom query methods for holidays."""
+
     pass
 
 
@@ -352,7 +375,10 @@ class SupervisionQuerySet(models.QuerySet, WeekQuerySetMixin):
 
             dates = [week[w] for w in range(0, 7)]
 
-            return self.filter(Q(substitutions__teacher=teacher, substitutions__date__in=dates) | Q(teacher=teacher))
+            return self.filter(
+                Q(substitutions__teacher=teacher, substitutions__date__in=dates)
+                | Q(teacher=teacher)
+            )
 
         return self
 
@@ -398,7 +424,9 @@ class TimetableQuerySet(models.QuerySet):
         else:
             return self.filter(room=room)
 
-    def filter_from_type(self, type_: TimetableType, pk: int) -> Optional[models.QuerySet]:
+    def filter_from_type(
+        self, type_: TimetableType, pk: int
+    ) -> Optional[models.QuerySet]:
         """Filter data for a group, teacher or room by provided type."""
 
         if type_ == TimetableType.GROUP:
@@ -457,7 +485,7 @@ class ExtraLessonQuerySet(TimetableQuerySet):
             period__weekday__lte=end.weekday(),
         )
 
-    def on_day(self, day:date):
+    def on_day(self, day: date):
         """Filter all extra lessons on a day."""
 
         return self.within_dates(day, day)
@@ -476,7 +504,11 @@ class GroupPropertiesMixin:
     @property
     def groups_to_show(self) -> models.QuerySet:
         groups = self.groups.all()
-        if groups.count() == 1 and groups[0].parent_groups.all() and get_site_preferences()["chronos__use_parent_groups"]:
+        if (
+            groups.count() == 1
+            and groups[0].parent_groups.all()
+            and get_site_preferences()["chronos__use_parent_groups"]
+        ):
             return groups[0].parent_groups.all()
         else:
             return groups
diff --git a/aleksis/apps/chronos/menus.py b/aleksis/apps/chronos/menus.py
index 592e6df9..4a07e4e8 100644
--- a/aleksis/apps/chronos/menus.py
+++ b/aleksis/apps/chronos/menus.py
@@ -17,7 +17,10 @@ MENUS = {
                     "url": "my_timetable",
                     "icon": "person",
                     "validators": [
-                        ("aleksis.core.util.predicates.permission_validator", "chronos.view_my_timetable"),
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "chronos.view_my_timetable",
+                        ),
                     ],
                 },
                 {
@@ -25,7 +28,10 @@ MENUS = {
                     "url": "all_timetables",
                     "icon": "grid_on",
                     "validators": [
-                        ("aleksis.core.util.predicates.permission_validator", "chronos.view_timetable_overview"),
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "chronos.view_timetable_overview",
+                        ),
                     ],
                 },
                 {
@@ -33,7 +39,10 @@ MENUS = {
                     "url": "lessons_day",
                     "icon": "calendar_today",
                     "validators": [
-                        ("aleksis.core.util.predicates.permission_validator", "chronos.view_lessons_day"),
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "chronos.view_lessons_day",
+                        ),
                     ],
                 },
                 {
@@ -41,7 +50,10 @@ MENUS = {
                     "url": "substitutions",
                     "icon": "update",
                     "validators": [
-                        ("aleksis.core.util.predicates.permission_validator", "chronos.view_substitutions"),
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "chronos.view_substitutions",
+                        ),
                     ],
                 },
             ],
diff --git a/aleksis/apps/chronos/migrations/0005_remove_school_related.py b/aleksis/apps/chronos/migrations/0005_remove_school_related.py
index f2ebba33..7d3ba123 100644
--- a/aleksis/apps/chronos/migrations/0005_remove_school_related.py
+++ b/aleksis/apps/chronos/migrations/0005_remove_school_related.py
@@ -6,69 +6,53 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('core', '0008_rename_fields_notification_activity'),
-        ('chronos', '0004_room_name_not_unique'),
+        ("core", "0008_rename_fields_notification_activity"),
+        ("chronos", "0004_room_name_not_unique"),
     ]
 
     operations = [
-        migrations.RemoveField(
-            model_name='lesson',
-            name='school',
-        ),
-        migrations.RemoveField(
-            model_name='lessonperiod',
-            name='school',
-        ),
+        migrations.RemoveField(model_name="lesson", name="school",),
+        migrations.RemoveField(model_name="lessonperiod", name="school",),
         migrations.AlterField(
-            model_name='lesson',
-            name='teachers',
-            field=models.ManyToManyField(related_name='lessons_as_teacher', to='core.Person'),
+            model_name="lesson",
+            name="teachers",
+            field=models.ManyToManyField(
+                related_name="lessons_as_teacher", to="core.Person"
+            ),
         ),
         migrations.AlterField(
-            model_name='room',
-            name='short_name',
-            field=models.CharField(max_length=10, unique=True, verbose_name='Short name, e.g. room number'),
+            model_name="room",
+            name="short_name",
+            field=models.CharField(
+                max_length=10, unique=True, verbose_name="Short name, e.g. room number"
+            ),
         ),
         migrations.AlterField(
-            model_name='subject',
-            name='abbrev',
-            field=models.CharField(max_length=10, unique=True, verbose_name='Abbreviation of subject in timetable'),
+            model_name="subject",
+            name="abbrev",
+            field=models.CharField(
+                max_length=10,
+                unique=True,
+                verbose_name="Abbreviation of subject in timetable",
+            ),
         ),
         migrations.AlterField(
-            model_name='subject',
-            name='name',
-            field=models.CharField(max_length=30, unique=True, verbose_name='Long name of subject'),
-        ),
-        migrations.AlterUniqueTogether(
-            name='lessonsubstitution',
-            unique_together={('lesson_period', 'week')},
-        ),
-        migrations.AlterUniqueTogether(
-            name='room',
-            unique_together=set(),
+            model_name="subject",
+            name="name",
+            field=models.CharField(
+                max_length=30, unique=True, verbose_name="Long name of subject"
+            ),
         ),
         migrations.AlterUniqueTogether(
-            name='subject',
-            unique_together=set(),
+            name="lessonsubstitution", unique_together={("lesson_period", "week")},
         ),
+        migrations.AlterUniqueTogether(name="room", unique_together=set(),),
+        migrations.AlterUniqueTogether(name="subject", unique_together=set(),),
         migrations.AlterUniqueTogether(
-            name='timeperiod',
-            unique_together={('weekday', 'period')},
-        ),
-        migrations.RemoveField(
-            model_name='lessonsubstitution',
-            name='school',
-        ),
-        migrations.RemoveField(
-            model_name='room',
-            name='school',
-        ),
-        migrations.RemoveField(
-            model_name='subject',
-            name='school',
-        ),
-        migrations.RemoveField(
-            model_name='timeperiod',
-            name='school',
+            name="timeperiod", unique_together={("weekday", "period")},
         ),
+        migrations.RemoveField(model_name="lessonsubstitution", name="school",),
+        migrations.RemoveField(model_name="room", name="school",),
+        migrations.RemoveField(model_name="subject", name="school",),
+        migrations.RemoveField(model_name="timeperiod", name="school",),
     ]
diff --git a/aleksis/apps/chronos/migrations/0006_extended_data.py b/aleksis/apps/chronos/migrations/0006_extended_data.py
index 71785e3f..6cbea640 100644
--- a/aleksis/apps/chronos/migrations/0006_extended_data.py
+++ b/aleksis/apps/chronos/migrations/0006_extended_data.py
@@ -7,13 +7,15 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0005_remove_school_related'),
+        ("chronos", "0005_remove_school_related"),
     ]
 
     operations = [
         migrations.AddField(
-            model_name='lessonperiod',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="lessonperiod",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py b/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py
index 87b517a8..ccefed73 100644
--- a/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py
+++ b/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py
@@ -9,272 +9,545 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0006_extended_data'),
+        ("chronos", "0006_extended_data"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='Absence',
+            name="Absence",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('date_start', models.DateField(null=True, verbose_name='Effective start date of absence')),
-                ('date_end', models.DateField(null=True, verbose_name='Effective end date of absence')),
-                ('comment', models.TextField(verbose_name='Comment', null=True, blank=True)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                (
+                    "date_start",
+                    models.DateField(
+                        null=True, verbose_name="Effective start date of absence"
+                    ),
+                ),
+                (
+                    "date_end",
+                    models.DateField(
+                        null=True, verbose_name="Effective end date of absence"
+                    ),
+                ),
+                (
+                    "comment",
+                    models.TextField(verbose_name="Comment", null=True, blank=True),
+                ),
             ],
             options={
-                'verbose_name': 'Absence',
-                'verbose_name_plural': 'Absences',
-                'ordering': ['date_start'],
+                "verbose_name": "Absence",
+                "verbose_name_plural": "Absences",
+                "ordering": ["date_start"],
             },
         ),
         migrations.CreateModel(
-            name='AbsenceReason',
+            name="AbsenceReason",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('title', models.CharField(max_length=50, verbose_name='Title')),
-                ('description', models.TextField(verbose_name='Description', null=True, blank=True)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                ("title", models.CharField(max_length=50, verbose_name="Title")),
+                (
+                    "description",
+                    models.TextField(verbose_name="Description", null=True, blank=True),
+                ),
             ],
             options={
-                'verbose_name': 'Absence reason',
-                'verbose_name_plural': 'Absence reasons',
+                "verbose_name": "Absence reason",
+                "verbose_name_plural": "Absence reasons",
             },
         ),
         migrations.CreateModel(
-            name='Event',
+            name="Event",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('title', models.CharField(max_length=50, verbose_name='Title')),
-                ('date_start', models.DateField(null=True, verbose_name='Effective start date of event')),
-                ('date_end', models.DateField(null=True, verbose_name='Effective end date of event')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                ("title", models.CharField(max_length=50, verbose_name="Title")),
+                (
+                    "date_start",
+                    models.DateField(
+                        null=True, verbose_name="Effective start date of event"
+                    ),
+                ),
+                (
+                    "date_end",
+                    models.DateField(
+                        null=True, verbose_name="Effective end date of event"
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Events',
-                'verbose_name_plural': 'Events',
-                'ordering': ['date_start'],
+                "verbose_name": "Events",
+                "verbose_name_plural": "Events",
+                "ordering": ["date_start"],
             },
         ),
         migrations.CreateModel(
-            name='Exam',
+            name="Exam",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('date', models.DateField(null=True, verbose_name='Date of exam')),
-                ('title', models.CharField(max_length=50, verbose_name='Title')),
-                ('comment', models.TextField(verbose_name='Comment', null=True, blank=True)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                ("date", models.DateField(null=True, verbose_name="Date of exam")),
+                ("title", models.CharField(max_length=50, verbose_name="Title")),
+                (
+                    "comment",
+                    models.TextField(verbose_name="Comment", null=True, blank=True),
+                ),
             ],
             options={
-                'verbose_name': 'Exam',
-                'verbose_name_plural': 'Exams',
-                'ordering': ['date'],
+                "verbose_name": "Exam",
+                "verbose_name_plural": "Exams",
+                "ordering": ["date"],
             },
         ),
         migrations.CreateModel(
-            name='Holiday',
+            name="Holiday",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('title', models.CharField(max_length=50, verbose_name='Title of the holidays')),
-                ('date_start', models.DateField(null=True, verbose_name='Effective start date of holidays')),
-                ('date_end', models.DateField(null=True, verbose_name='Effective end date of holidays')),
-                ('comments', models.TextField(verbose_name='Comments', null=True, blank=True)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                (
+                    "title",
+                    models.CharField(
+                        max_length=50, verbose_name="Title of the holidays"
+                    ),
+                ),
+                (
+                    "date_start",
+                    models.DateField(
+                        null=True, verbose_name="Effective start date of holidays"
+                    ),
+                ),
+                (
+                    "date_end",
+                    models.DateField(
+                        null=True, verbose_name="Effective end date of holidays"
+                    ),
+                ),
+                (
+                    "comments",
+                    models.TextField(verbose_name="Comments", null=True, blank=True),
+                ),
             ],
             options={
-                'verbose_name': 'Holiday',
-                'verbose_name_plural': 'Holidays',
-                'ordering': ['date_start'],
+                "verbose_name": "Holiday",
+                "verbose_name_plural": "Holidays",
+                "ordering": ["date_start"],
             },
         ),
         migrations.CreateModel(
-            name='SupervisionArea',
+            name="SupervisionArea",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('short_name', models.CharField(max_length=10, verbose_name='Short name')),
-                ('name', models.CharField(max_length=50, verbose_name='Long name')),
-                ('colour_fg', colorfield.fields.ColorField(default='#000000', max_length=18)),
-                ('colour_bg', colorfield.fields.ColorField(default='#FFFFFF', max_length=18)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                (
+                    "short_name",
+                    models.CharField(max_length=10, verbose_name="Short name"),
+                ),
+                ("name", models.CharField(max_length=50, verbose_name="Long name")),
+                (
+                    "colour_fg",
+                    colorfield.fields.ColorField(default="#000000", max_length=18),
+                ),
+                (
+                    "colour_bg",
+                    colorfield.fields.ColorField(default="#FFFFFF", max_length=18),
+                ),
             ],
             options={
-                'verbose_name': 'Supervision areas',
-                'verbose_name_plural': 'Supervision areas',
-                'ordering': ['name'],
+                "verbose_name": "Supervision areas",
+                "verbose_name_plural": "Supervision areas",
+                "ordering": ["name"],
             },
         ),
         migrations.CreateModel(
-            name='Break',
+            name="Break",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('short_name', models.CharField(max_length=10, verbose_name='Short name')),
-                ('name', models.CharField(max_length=50, verbose_name='Long name')),
-                ('weekday', models.PositiveSmallIntegerField(
-                    choices=[(0, 'Montag'), (1, 'Dienstag'), (2, 'Mittwoch'), (3, 'Donnerstag'), (4, 'Freitag'),
-                             (5, 'Samstag'), (6, 'Sonntag')], verbose_name='Week day')),
-                ('time_start', models.TimeField(verbose_name='Start time')),
-                ('time_end', models.TimeField(verbose_name='End time')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                (
+                    "short_name",
+                    models.CharField(max_length=10, verbose_name="Short name"),
+                ),
+                ("name", models.CharField(max_length=50, verbose_name="Long name")),
+                (
+                    "weekday",
+                    models.PositiveSmallIntegerField(
+                        choices=[
+                            (0, "Montag"),
+                            (1, "Dienstag"),
+                            (2, "Mittwoch"),
+                            (3, "Donnerstag"),
+                            (4, "Freitag"),
+                            (5, "Samstag"),
+                            (6, "Sonntag"),
+                        ],
+                        verbose_name="Week day",
+                    ),
+                ),
+                ("time_start", models.TimeField(verbose_name="Start time")),
+                ("time_end", models.TimeField(verbose_name="End time")),
             ],
             options={
-                'verbose_name': 'Break',
-                'verbose_name_plural': 'Breaks',
-                'ordering': ['weekday', 'time_start'],
+                "verbose_name": "Break",
+                "verbose_name_plural": "Breaks",
+                "ordering": ["weekday", "time_start"],
             },
         ),
         migrations.CreateModel(
-            name='Supervision',
+            name="Supervision",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Supervision',
-                'verbose_name_plural': 'Supervisions',
-                'ordering': ['area', 'break_item'],
+                "verbose_name": "Supervision",
+                "verbose_name_plural": "Supervisions",
+                "ordering": ["area", "break_item"],
             },
         ),
         migrations.CreateModel(
-            name='SupervisionSubstitution',
+            name="SupervisionSubstitution",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('date', models.DateField(verbose_name='Date')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                ("date", models.DateField(verbose_name="Date")),
             ],
             options={
-                'verbose_name': 'Supervision substitution',
-                'verbose_name_plural': 'Supervision substitutions',
-                'ordering': ['date', 'supervision'],
+                "verbose_name": "Supervision substitution",
+                "verbose_name_plural": "Supervision substitutions",
+                "ordering": ["date", "supervision"],
             },
         ),
         migrations.AddIndex(
-            model_name='holiday',
-            index=models.Index(fields=['date_start', 'date_end'], name='chronos_hol_date_st_a47004_idx'),
+            model_name="holiday",
+            index=models.Index(
+                fields=["date_start", "date_end"], name="chronos_hol_date_st_a47004_idx"
+            ),
         ),
         migrations.AddField(
-            model_name='exam',
-            name='lesson',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exams', to='chronos.Lesson'),
+            model_name="exam",
+            name="lesson",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="exams",
+                to="chronos.Lesson",
+            ),
         ),
         migrations.AddField(
-            model_name='exam',
-            name='period_from',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective start period of exam'),
+            model_name="exam",
+            name="period_from",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective start period of exam",
+            ),
         ),
         migrations.AddField(
-            model_name='exam',
-            name='period_to',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective end period of exam'),
+            model_name="exam",
+            name="period_to",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective end period of exam",
+            ),
         ),
         migrations.AddField(
-            model_name='event',
-            name='absence_reason',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absence_reason', to='chronos.AbsenceReason', verbose_name='Absence reason'),
+            model_name="event",
+            name="absence_reason",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="absence_reason",
+                to="chronos.AbsenceReason",
+                verbose_name="Absence reason",
+            ),
         ),
         migrations.AddField(
-            model_name='event',
-            name='teachers',
-            field=models.ManyToManyField(related_name='events', to='core.Person', verbose_name='Teachers'),
+            model_name="event",
+            name="teachers",
+            field=models.ManyToManyField(
+                related_name="events", to="core.Person", verbose_name="Teachers"
+            ),
         ),
         migrations.AddField(
-            model_name='event',
-            name='period_from',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective start period of event'),
+            model_name="event",
+            name="period_from",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective start period of event",
+            ),
         ),
         migrations.AddField(
-            model_name='event',
-            name='period_to',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective end period of event'),
+            model_name="event",
+            name="period_to",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective end period of event",
+            ),
         ),
         migrations.AddField(
-            model_name='event',
-            name='rooms',
-            field=models.ManyToManyField(related_name='events', to='chronos.Room', verbose_name='Rooms'),
+            model_name="event",
+            name="rooms",
+            field=models.ManyToManyField(
+                related_name="events", to="chronos.Room", verbose_name="Rooms"
+            ),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='period_from',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective start period of absence'),
+            model_name="absence",
+            name="period_from",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective start period of absence",
+            ),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='period_to',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Effective end period of absence'),
+            model_name="absence",
+            name="period_to",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="+",
+                to="chronos.TimePeriod",
+                verbose_name="Effective end period of absence",
+            ),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='person',
-            field=models.ManyToManyField(related_name='absences', to='core.Person'),
+            model_name="absence",
+            name="person",
+            field=models.ManyToManyField(related_name="absences", to="core.Person"),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='reason',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='chronos.AbsenceReason'),
+            model_name="absence",
+            name="reason",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="absences",
+                to="chronos.AbsenceReason",
+            ),
         ),
         migrations.AddIndex(
-            model_name='exam',
-            index=models.Index(fields=['date'], name='chronos_exa_date_5ba442_idx'),
+            model_name="exam",
+            index=models.Index(fields=["date"], name="chronos_exa_date_5ba442_idx"),
         ),
         migrations.AddIndex(
-            model_name='event',
-            index=models.Index(fields=['period_from', 'period_to', 'date_start', 'date_end'], name='chronos_eve_periodf_56eb18_idx'),
+            model_name="event",
+            index=models.Index(
+                fields=["period_from", "period_to", "date_start", "date_end"],
+                name="chronos_eve_periodf_56eb18_idx",
+            ),
         ),
         migrations.AddIndex(
-            model_name='absence',
-            index=models.Index(fields=['date_start', 'date_end'], name='chronos_abs_date_st_337ff5_idx'),
+            model_name="absence",
+            index=models.Index(
+                fields=["date_start", "date_end"], name="chronos_abs_date_st_337ff5_idx"
+            ),
         ),
         migrations.AddField(
-            model_name='lessonsubstitution',
-            name='cancelled_for_teachers',
-            field=models.BooleanField(default=False, verbose_name='Cancelled for teachers?'),
+            model_name="lessonsubstitution",
+            name="cancelled_for_teachers",
+            field=models.BooleanField(
+                default=False, verbose_name="Cancelled for teachers?"
+            ),
         ),
         migrations.AddField(
-            model_name='lessonsubstitution',
-            name='comment',
-            field=models.TextField(blank=True, null=True, verbose_name='Comment'),
+            model_name="lessonsubstitution",
+            name="comment",
+            field=models.TextField(blank=True, null=True, verbose_name="Comment"),
         ),
         migrations.AlterField(
-            model_name='lessonsubstitution',
-            name='cancelled',
-            field=models.BooleanField(default=False, verbose_name='Cancelled?'),
+            model_name="lessonsubstitution",
+            name="cancelled",
+            field=models.BooleanField(default=False, verbose_name="Cancelled?"),
         ),
         migrations.AddField(
-            model_name='event',
-            name='groups',
-            field=models.ManyToManyField(related_name='events', to='core.Group', verbose_name='Groups'),
+            model_name="event",
+            name="groups",
+            field=models.ManyToManyField(
+                related_name="events", to="core.Group", verbose_name="Groups"
+            ),
         ),
         migrations.AddField(
-            model_name='supervisionsubstitution',
-            name='supervision',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='substitutions',
-                                    to='chronos.Supervision', verbose_name='Supervision'),
+            model_name="supervisionsubstitution",
+            name="supervision",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="substitutions",
+                to="chronos.Supervision",
+                verbose_name="Supervision",
+            ),
         ),
         migrations.AddField(
-            model_name='supervisionsubstitution',
-            name='teacher',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
-                                    related_name='substituted_supervisions', to='core.Person', verbose_name='Teacher'),
+            model_name="supervisionsubstitution",
+            name="teacher",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="substituted_supervisions",
+                to="core.Person",
+                verbose_name="Teacher",
+            ),
         ),
         migrations.AddField(
-            model_name='supervision',
-            name='area',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='supervisions',
-                                    to='chronos.SupervisionArea', verbose_name='Supervision area'),
+            model_name="supervision",
+            name="area",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="supervisions",
+                to="chronos.SupervisionArea",
+                verbose_name="Supervision area",
+            ),
         ),
         migrations.AddField(
-            model_name='supervision',
-            name='break_item',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='supervisions',
-                                    to='chronos.Break', verbose_name='Break'),
+            model_name="supervision",
+            name="break_item",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="supervisions",
+                to="chronos.Break",
+                verbose_name="Break",
+            ),
         ),
         migrations.AddField(
-            model_name='supervision',
-            name='teacher',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='supervisions',
-                                    to='core.Person', verbose_name='Teacher'),
+            model_name="supervision",
+            name="teacher",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="supervisions",
+                to="core.Person",
+                verbose_name="Teacher",
+            ),
         ),
         migrations.AddIndex(
-            model_name='break',
-            index=models.Index(fields=['weekday', 'time_start', 'time_end'], name='chronos_bre_weekday_165338_idx'),
+            model_name="break",
+            index=models.Index(
+                fields=["weekday", "time_start", "time_end"],
+                name="chronos_bre_weekday_165338_idx",
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0008_break_period.py b/aleksis/apps/chronos/migrations/0008_break_period.py
index 740fd91b..971432ab 100644
--- a/aleksis/apps/chronos/migrations/0008_break_period.py
+++ b/aleksis/apps/chronos/migrations/0008_break_period.py
@@ -7,38 +7,45 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0007_advanced_models_from_untis'),
+        ("chronos", "0007_advanced_models_from_untis"),
     ]
 
     operations = [
         migrations.RemoveIndex(
-            model_name='break',
-            name='chronos_bre_weekday_165338_idx',
-        ),
-        migrations.RemoveField(
-            model_name='break',
-            name='time_end',
-        ),
-        migrations.RemoveField(
-            model_name='break',
-            name='time_start',
-        ),
-        migrations.RemoveField(
-            model_name='break',
-            name='weekday',
+            model_name="break", name="chronos_bre_weekday_165338_idx",
         ),
+        migrations.RemoveField(model_name="break", name="time_end",),
+        migrations.RemoveField(model_name="break", name="time_start",),
+        migrations.RemoveField(model_name="break", name="weekday",),
         migrations.AddField(
-            model_name='break',
-            name='after_period',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='break_after', to='chronos.TimePeriod', verbose_name='Effective start of break'),
+            model_name="break",
+            name="after_period",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="break_after",
+                to="chronos.TimePeriod",
+                verbose_name="Effective start of break",
+            ),
         ),
         migrations.AddField(
-            model_name='break',
-            name='before_period',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='break_before', to='chronos.TimePeriod', verbose_name='Effective end of break'),
+            model_name="break",
+            name="before_period",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="break_before",
+                to="chronos.TimePeriod",
+                verbose_name="Effective end of break",
+            ),
         ),
         migrations.AddIndex(
-            model_name='break',
-            index=models.Index(fields=['after_period', 'before_period'], name='chronos_bre_after_p_0f28d3_idx'),
+            model_name="break",
+            index=models.Index(
+                fields=["after_period", "before_period"],
+                name="chronos_bre_after_p_0f28d3_idx",
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0009_extended_data.py b/aleksis/apps/chronos/migrations/0009_extended_data.py
index 6c8ff264..ed65071f 100644
--- a/aleksis/apps/chronos/migrations/0009_extended_data.py
+++ b/aleksis/apps/chronos/migrations/0009_extended_data.py
@@ -7,33 +7,43 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0008_break_period'),
+        ("chronos", "0008_break_period"),
     ]
 
     operations = [
         migrations.AddField(
-            model_name='lesson',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="lesson",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
         migrations.AddField(
-            model_name='lessonsubstitution',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="lessonsubstitution",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
         migrations.AddField(
-            model_name='room',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="room",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
         migrations.AddField(
-            model_name='subject',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="subject",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
         migrations.AddField(
-            model_name='timeperiod',
-            name='extended_data',
-            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+            model_name="timeperiod",
+            name="extended_data",
+            field=django.contrib.postgres.fields.jsonb.JSONField(
+                default=dict, editable=False
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0010_absence_reason_name.py b/aleksis/apps/chronos/migrations/0010_absence_reason_name.py
index 7c57327a..95f05e8b 100644
--- a/aleksis/apps/chronos/migrations/0010_absence_reason_name.py
+++ b/aleksis/apps/chronos/migrations/0010_absence_reason_name.py
@@ -7,27 +7,29 @@ from django.db.models import F
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0009_extended_data'),
+        ("chronos", "0009_extended_data"),
     ]
 
     operations = [
         migrations.AddField(
-            model_name='absencereason',
-            name='name',
-            field=models.CharField(default=F("description"), blank=True, max_length=255, null=True, verbose_name='Name'),
+            model_name="absencereason",
+            name="name",
+            field=models.CharField(
+                default=F("description"),
+                blank=True,
+                max_length=255,
+                null=True,
+                verbose_name="Name",
+            ),
         ),
         migrations.AddField(
-            model_name='absencereason',
-            name='short_name',
-            field=models.CharField(default=F("title"), max_length=255, verbose_name='Short name'),
+            model_name="absencereason",
+            name="short_name",
+            field=models.CharField(
+                default=F("title"), max_length=255, verbose_name="Short name"
+            ),
             preserve_default=False,
         ),
-        migrations.RemoveField(
-            model_name='absencereason',
-            name='description',
-        ),
-        migrations.RemoveField(
-            model_name='absencereason',
-            name='title',
-        ),
+        migrations.RemoveField(model_name="absencereason", name="description",),
+        migrations.RemoveField(model_name="absencereason", name="title",),
     ]
diff --git a/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py b/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py
index 008a723a..cf7df94c 100644
--- a/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py
+++ b/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py
@@ -7,27 +7,42 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0010_absence_reason_name'),
+        ("chronos", "0010_absence_reason_name"),
     ]
 
     operations = [
-        migrations.RemoveField(
-            model_name='absence',
-            name='person',
-        ),
+        migrations.RemoveField(model_name="absence", name="person",),
         migrations.AddField(
-            model_name='absence',
-            name='group',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Group'),
+            model_name="absence",
+            name="group",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="absences",
+                to="core.Group",
+            ),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='room',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='chronos.Room'),
+            model_name="absence",
+            name="room",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="absences",
+                to="chronos.Room",
+            ),
         ),
         migrations.AddField(
-            model_name='absence',
-            name='teacher',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Person'),
+            model_name="absence",
+            name="teacher",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="absences",
+                to="core.Person",
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py b/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py
index 4e661196..5bdaaee5 100644
--- a/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py
+++ b/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py
@@ -6,12 +6,9 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0011_absence_for_groups_and_rooms'),
+        ("chronos", "0011_absence_for_groups_and_rooms"),
     ]
 
     operations = [
-        migrations.RemoveField(
-            model_name='event',
-            name='absence_reason',
-        ),
+        migrations.RemoveField(model_name="event", name="absence_reason",),
     ]
diff --git a/aleksis/apps/chronos/migrations/0013_event_title_optional.py b/aleksis/apps/chronos/migrations/0013_event_title_optional.py
index 4bc05c39..6f18311e 100644
--- a/aleksis/apps/chronos/migrations/0013_event_title_optional.py
+++ b/aleksis/apps/chronos/migrations/0013_event_title_optional.py
@@ -6,13 +6,15 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0012_event_remove_absence_reason'),
+        ("chronos", "0012_event_remove_absence_reason"),
     ]
 
     operations = [
         migrations.AlterField(
-            model_name='event',
-            name='title',
-            field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Title'),
+            model_name="event",
+            name="title",
+            field=models.CharField(
+                blank=True, max_length=255, null=True, verbose_name="Title"
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0014_extra_lesson.py b/aleksis/apps/chronos/migrations/0014_extra_lesson.py
index b0610a5e..d3a497d9 100644
--- a/aleksis/apps/chronos/migrations/0014_extra_lesson.py
+++ b/aleksis/apps/chronos/migrations/0014_extra_lesson.py
@@ -9,45 +9,88 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0013_event_title_optional'),
+        ("chronos", "0013_event_title_optional"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='ExtraLesson',
+            name="ExtraLesson",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
-                ('week', models.IntegerField(default=calendarweek.calendarweek.CalendarWeek.current_week, verbose_name='Week')),
-                ('comment', models.CharField(blank=True, max_length=255, null=True, verbose_name='Comment')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
+                (
+                    "week",
+                    models.IntegerField(
+                        default=calendarweek.calendarweek.CalendarWeek.current_week,
+                        verbose_name="Week",
+                    ),
+                ),
+                (
+                    "comment",
+                    models.CharField(
+                        blank=True, max_length=255, null=True, verbose_name="Comment"
+                    ),
+                ),
             ],
-            options={
-                'abstract': False,
-            },
+            options={"abstract": False,},
         ),
         migrations.AddField(
-            model_name='extralesson',
-            name='groups',
-            field=models.ManyToManyField(related_name='extra_lessons', to='core.Group', verbose_name='Groups'),
+            model_name="extralesson",
+            name="groups",
+            field=models.ManyToManyField(
+                related_name="extra_lessons", to="core.Group", verbose_name="Groups"
+            ),
         ),
         migrations.AddField(
-            model_name='extralesson',
-            name='period',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.TimePeriod'),
+            model_name="extralesson",
+            name="period",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="extra_lessons",
+                to="chronos.TimePeriod",
+            ),
         ),
         migrations.AddField(
-            model_name='extralesson',
-            name='room',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.Room', verbose_name='Room'),
+            model_name="extralesson",
+            name="room",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="extra_lessons",
+                to="chronos.Room",
+                verbose_name="Room",
+            ),
         ),
         migrations.AddField(
-            model_name='extralesson',
-            name='subject',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.Subject', verbose_name='Subject'),
+            model_name="extralesson",
+            name="subject",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="extra_lessons",
+                to="chronos.Subject",
+                verbose_name="Subject",
+            ),
         ),
         migrations.AddField(
-            model_name='extralesson',
-            name='teachers',
-            field=models.ManyToManyField(related_name='extra_lessons_as_teacher', to='core.Person', verbose_name='Teachers'),
+            model_name="extralesson",
+            name="teachers",
+            field=models.ManyToManyField(
+                related_name="extra_lessons_as_teacher",
+                to="core.Person",
+                verbose_name="Teachers",
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py b/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py
index 5d79636e..4912dd0d 100644
--- a/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py
+++ b/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py
@@ -7,17 +7,14 @@ from django.db.models import F
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0014_extra_lesson'),
+        ("chronos", "0014_extra_lesson"),
     ]
 
     operations = [
         migrations.RenameField(
-            model_name='subject',
-            old_name='abbrev',
-            new_name='short_name',
+            model_name="subject", old_name="abbrev", new_name="short_name",
         ),
         migrations.AlterModelOptions(
-            name='subject',
-            options={'ordering': ['name', 'short_name']},
+            name="subject", options={"ordering": ["name", "short_name"]},
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py b/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py
index 785e2782..b43b2bf1 100644
--- a/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py
+++ b/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py
@@ -7,19 +7,36 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('chronos', '0015_rename_abbrev_to_short_name'),
+        ("chronos", "0015_rename_abbrev_to_short_name"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='GlobalPermissions',
+            name="GlobalPermissions",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "extended_data",
+                    django.contrib.postgres.fields.jsonb.JSONField(
+                        default=dict, editable=False
+                    ),
+                ),
             ],
             options={
-                'permissions': (('view_all_timetables', 'Can view all timetables'), ('view_timetable_overview', 'Can view timetable overview'), ('view_lessons_day', 'Can view all lessons per day')),
-                'managed': False,
+                "permissions": (
+                    ("view_all_timetables", "Can view all timetables"),
+                    ("view_timetable_overview", "Can view timetable overview"),
+                    ("view_lessons_day", "Can view all lessons per day"),
+                ),
+                "managed": False,
             },
         ),
     ]
diff --git a/aleksis/apps/chronos/model_extensions.py b/aleksis/apps/chronos/model_extensions.py
index 1a1bcd59..2877278e 100644
--- a/aleksis/apps/chronos/model_extensions.py
+++ b/aleksis/apps/chronos/model_extensions.py
@@ -93,4 +93,8 @@ def for_timetables(cls):
 
 
 Announcement.class_method(for_timetables)
-Announcement.field(show_in_timetables=BooleanField(verbose_name=_("Show announcement in timetable views?")))
+Announcement.field(
+    show_in_timetables=BooleanField(
+        verbose_name=_("Show announcement in timetable views?")
+    )
+)
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 556f3a1f..595ba172 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -3,9 +3,19 @@ from __future__ import annotations
 from datetime import date, datetime, timedelta, time
 from typing import Dict, Optional, Tuple, Union
 
-from aleksis.apps.chronos.managers import GroupPropertiesMixin, TeacherPropertiesMixin, LessonSubstitutionManager, \
-    LessonSubstitutionQuerySet, LessonPeriodManager, LessonPeriodQuerySet, AbsenceQuerySet, HolidayQuerySet, \
-    SupervisionQuerySet, EventQuerySet, ExtraLessonQuerySet
+from aleksis.apps.chronos.managers import (
+    GroupPropertiesMixin,
+    TeacherPropertiesMixin,
+    LessonSubstitutionManager,
+    LessonSubstitutionQuerySet,
+    LessonPeriodManager,
+    LessonPeriodQuerySet,
+    AbsenceQuerySet,
+    HolidayQuerySet,
+    SupervisionQuerySet,
+    EventQuerySet,
+    ExtraLessonQuerySet,
+)
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.db.models import Max, Min, Q
@@ -33,17 +43,16 @@ class TimePeriod(ExtensibleModel):
     WEEKDAY_CHOICES = list(enumerate(i18n_day_names_lazy()))
     WEEKDAY_CHOICES_SHORT = list(enumerate(i18n_day_abbrs_lazy()))
 
-    weekday = models.PositiveSmallIntegerField(verbose_name=_("Week day"), choices=WEEKDAY_CHOICES)
+    weekday = models.PositiveSmallIntegerField(
+        verbose_name=_("Week day"), choices=WEEKDAY_CHOICES
+    )
     period = models.PositiveSmallIntegerField(verbose_name=_("Number of period"))
 
     time_start = models.TimeField(verbose_name=_("Start time"))
     time_end = models.TimeField(verbose_name=_("End time"))
 
     def __str__(self) -> str:
-        return "{}, {}.".format(
-            self.get_weekday_display(),
-            self.period,
-        )
+        return "{}, {}.".format(self.get_weekday_display(), self.period,)
 
     @classmethod
     def get_times_dict(cls) -> Dict[int, Tuple[datetime, datetime]]:
@@ -68,7 +77,9 @@ class TimePeriod(ExtensibleModel):
         return wanted_week[self.weekday]
 
     @classmethod
-    def get_next_relevant_day(cls, day: Optional[date] = None, time: Optional[time] = None, prev: bool = False) -> date:
+    def get_next_relevant_day(
+        cls, day: Optional[date] = None, time: Optional[time] = None, prev: bool = False
+    ) -> date:
         """ Returns next (previous) day with lessons depending on date and time """
 
         if day is None:
@@ -109,11 +120,15 @@ class TimePeriod(ExtensibleModel):
 
     @classproperty
     def period_min(cls) -> int:
-        return cls.objects.aggregate(period__min=Coalesce(Min("period"), 1)).get("period__min")
+        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")
+        return cls.objects.aggregate(period__max=Coalesce(Max("period"), 7)).get(
+            "period__max"
+        )
 
     @classproperty
     def time_min(cls) -> Optional[time]:
@@ -125,11 +140,15 @@ class TimePeriod(ExtensibleModel):
 
     @classproperty
     def weekday_min(cls) -> int:
-        return cls.objects.aggregate(weekday__min=Coalesce(Min("weekday"), 0)).get("weekday__min")
+        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")
+        return cls.objects.aggregate(weekday__max=Coalesce(Max("weekday"), 6)).get(
+            "weekday__max"
+        )
 
     class Meta:
         unique_together = [["weekday", "period"]]
@@ -140,7 +159,9 @@ class TimePeriod(ExtensibleModel):
 
 
 class Subject(ExtensibleModel):
-    short_name = models.CharField(verbose_name=_("Short name"), max_length=255, unique=True)
+    short_name = models.CharField(
+        verbose_name=_("Short name"), max_length=255, unique=True
+    )
     name = models.CharField(verbose_name=_("Long name"), max_length=255, unique=True)
 
     colour_fg = ColorField(verbose_name=_("Foreground colour"), blank=True)
@@ -156,7 +177,9 @@ class Subject(ExtensibleModel):
 
 
 class Room(ExtensibleModel):
-    short_name = models.CharField(verbose_name=_("Short name"), max_length=255, unique=True)
+    short_name = models.CharField(
+        verbose_name=_("Short name"), max_length=255, unique=True
+    )
     name = models.CharField(verbose_name=_("Long name"), max_length=255)
 
     def __str__(self) -> str:
@@ -168,13 +191,25 @@ class Room(ExtensibleModel):
         verbose_name_plural = _("Rooms")
 
 
-
-
 class Lesson(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
-    subject = models.ForeignKey("Subject", on_delete=models.CASCADE, related_name="lessons", verbose_name=_("Subject"))
-    teachers = models.ManyToManyField("core.Person", related_name="lessons_as_teacher", verbose_name=_("Teachers"))
-    periods = models.ManyToManyField("TimePeriod", related_name="lessons", through="LessonPeriod", verbose_name=_("Periods"))
-    groups = models.ManyToManyField("core.Group", related_name="lessons", verbose_name=_("Groups"))
+    subject = models.ForeignKey(
+        "Subject",
+        on_delete=models.CASCADE,
+        related_name="lessons",
+        verbose_name=_("Subject"),
+    )
+    teachers = models.ManyToManyField(
+        "core.Person", related_name="lessons_as_teacher", verbose_name=_("Teachers")
+    )
+    periods = models.ManyToManyField(
+        "TimePeriod",
+        related_name="lessons",
+        through="LessonPeriod",
+        verbose_name=_("Periods"),
+    )
+    groups = models.ManyToManyField(
+        "core.Group", related_name="lessons", verbose_name=_("Groups")
+    )
 
     date_start = models.DateField(verbose_name=_("Start date"), null=True)
     date_end = models.DateField(verbose_name=_("End date"), null=True)
@@ -188,9 +223,7 @@ class Lesson(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
 
     def __str__(self):
         return "{}, {}, {}".format(
-            format_m2m(self.groups),
-            self.subject.short_name,
-            format_m2m(self.teachers),
+            format_m2m(self.groups), self.subject.short_name, format_m2m(self.teachers),
         )
 
     class Meta:
@@ -203,9 +236,13 @@ class Lesson(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
 class LessonSubstitution(ExtensibleModel):
     objects = LessonSubstitutionManager.from_queryset(LessonSubstitutionQuerySet)()
 
-    week = models.IntegerField(verbose_name=_("Week"), default=CalendarWeek.current_week)
+    week = models.IntegerField(
+        verbose_name=_("Week"), default=CalendarWeek.current_week
+    )
 
-    lesson_period = models.ForeignKey("LessonPeriod", models.CASCADE, "substitutions", verbose_name=_("Lesson period"))
+    lesson_period = models.ForeignKey(
+        "LessonPeriod", models.CASCADE, "substitutions", verbose_name=_("Lesson period")
+    )
 
     subject = models.ForeignKey(
         "Subject",
@@ -216,18 +253,27 @@ class LessonSubstitution(ExtensibleModel):
         verbose_name=_("Subject"),
     )
     teachers = models.ManyToManyField(
-        "core.Person", related_name="lesson_substitutions", blank=True, verbose_name=_("Teachers")
+        "core.Person",
+        related_name="lesson_substitutions",
+        blank=True,
+        verbose_name=_("Teachers"),
+    )
+    room = models.ForeignKey(
+        "Room", models.CASCADE, null=True, blank=True, verbose_name=_("Room")
     )
-    room = models.ForeignKey("Room", models.CASCADE, null=True, blank=True, verbose_name=_("Room"))
 
     cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled?"))
-    cancelled_for_teachers = models.BooleanField(default=False, verbose_name=_("Cancelled for teachers?"))
+    cancelled_for_teachers = models.BooleanField(
+        default=False, verbose_name=_("Cancelled for teachers?")
+    )
 
     comment = models.TextField(verbose_name=_("Comment"), blank=True, null=True)
 
     def clean(self) -> None:
         if self.subject and self.cancelled:
-            raise ValidationError(_("Lessons can only be either substituted or cancelled."))
+            raise ValidationError(
+                _("Lessons can only be either substituted or cancelled.")
+            )
 
     @property
     def date(self):
@@ -260,10 +306,26 @@ class LessonPeriod(ExtensibleModel):
 
     objects = LessonPeriodManager.from_queryset(LessonPeriodQuerySet)()
 
-    lesson = models.ForeignKey("Lesson", models.CASCADE, related_name="lesson_periods", verbose_name=_("Lesson"))
-    period = models.ForeignKey("TimePeriod", models.CASCADE, related_name="lesson_periods", verbose_name=_("Time period"))
+    lesson = models.ForeignKey(
+        "Lesson",
+        models.CASCADE,
+        related_name="lesson_periods",
+        verbose_name=_("Lesson"),
+    )
+    period = models.ForeignKey(
+        "TimePeriod",
+        models.CASCADE,
+        related_name="lesson_periods",
+        verbose_name=_("Time period"),
+    )
 
-    room = models.ForeignKey("Room", models.CASCADE, null=True, related_name="lesson_periods", verbose_name=_("Room"))
+    room = models.ForeignKey(
+        "Room",
+        models.CASCADE,
+        null=True,
+        related_name="lesson_periods",
+        verbose_name=_("Room"),
+    )
 
     def get_substitution(self, week: Optional[int] = None) -> LessonSubstitution:
         wanted_week = week or getattr(self, "_week", None) or CalendarWeek().week
@@ -301,13 +363,15 @@ class LessonPeriod(ExtensibleModel):
         return self.lesson.groups
 
     def __str__(self) -> str:
-        return "{}, {}".format(
-            str(self.period),
-            str(self.lesson)
-        )
+        return "{}, {}".format(str(self.period), str(self.lesson))
 
     class Meta:
-        ordering = ["lesson__date_start", "period__weekday", "period__period", "lesson__subject"]
+        ordering = [
+            "lesson__date_start",
+            "period__weekday",
+            "period__period",
+            "lesson__subject",
+        ]
         indexes = [models.Index(fields=["lesson", "period"])]
         verbose_name = _("Lesson period")
         verbose_name_plural = _("Lesson periods")
@@ -317,11 +381,13 @@ class TimetableWidget(DashboardWidget):
     template = "chronos/widget.html"
 
     def get_context(self):
-        from aleksis.apps.chronos.util.build import build_timetable # noqa
+        from aleksis.apps.chronos.util.build import build_timetable  # noqa
 
         request = get_request()
         context = {"has_plan": True}
-        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(
+            timezone.now().date(), datetime.now().time()
+        )
 
         if has_person(request.user):
             person = request.user.person
@@ -345,9 +411,7 @@ class TimetableWidget(DashboardWidget):
 
         return context
 
-    media = Media(css={
-        "all": ("css/chronos/timetable.css",)
-    })
+    media = Media(css={"all": ("css/chronos/timetable.css",)})
 
     class Meta:
         proxy = True
@@ -357,7 +421,9 @@ class TimetableWidget(DashboardWidget):
 
 class AbsenceReason(ExtensibleModel):
     short_name = models.CharField(verbose_name=_("Short name"), max_length=255)
-    name = models.CharField(verbose_name=_("Name"), blank=True, null=True, max_length=255)
+    name = models.CharField(
+        verbose_name=_("Name"), blank=True, null=True, max_length=255
+    )
 
     def __str__(self):
         if self.name:
@@ -373,16 +439,56 @@ class AbsenceReason(ExtensibleModel):
 class Absence(ExtensibleModel):
     objects = models.Manager.from_queryset(AbsenceQuerySet)()
 
-    reason = models.ForeignKey("AbsenceReason", on_delete=models.SET_NULL, related_name="absences", blank=True, null=True, verbose_name=_("Absence reason"))
+    reason = models.ForeignKey(
+        "AbsenceReason",
+        on_delete=models.SET_NULL,
+        related_name="absences",
+        blank=True,
+        null=True,
+        verbose_name=_("Absence reason"),
+    )
 
-    teacher = models.ForeignKey("core.Person", on_delete=models.CASCADE, related_name="absences", null=True, blank=True, verbose_name=_("Teacher"))
-    group = models.ForeignKey("core.Group", on_delete=models.CASCADE, related_name="absences", null=True, blank=True, verbose_name=_("Group"))
-    room = models.ForeignKey("Room", on_delete=models.CASCADE, related_name="absences", null=True, blank=True, verbose_name=_("Room"))
+    teacher = models.ForeignKey(
+        "core.Person",
+        on_delete=models.CASCADE,
+        related_name="absences",
+        null=True,
+        blank=True,
+        verbose_name=_("Teacher"),
+    )
+    group = models.ForeignKey(
+        "core.Group",
+        on_delete=models.CASCADE,
+        related_name="absences",
+        null=True,
+        blank=True,
+        verbose_name=_("Group"),
+    )
+    room = models.ForeignKey(
+        "Room",
+        on_delete=models.CASCADE,
+        related_name="absences",
+        null=True,
+        blank=True,
+        verbose_name=_("Room"),
+    )
 
     date_start = models.DateField(verbose_name=_("Start date"), null=True)
     date_end = models.DateField(verbose_name=_("End date"), null=True)
-    period_from = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("Start period"), null=True, related_name="+")
-    period_to = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("End period"), null=True, related_name="+")
+    period_from = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("Start period"),
+        null=True,
+        related_name="+",
+    )
+    period_to = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("End period"),
+        null=True,
+        related_name="+",
+    )
     comment = models.TextField(verbose_name=_("Comment"), blank=True, null=True)
 
     def __str__(self):
@@ -403,11 +509,28 @@ class Absence(ExtensibleModel):
 
 
 class Exam(ExtensibleModel):
-    lesson = models.ForeignKey("Lesson", on_delete=models.CASCADE, related_name="exams", verbose_name=_("Lesson"))
+    lesson = models.ForeignKey(
+        "Lesson",
+        on_delete=models.CASCADE,
+        related_name="exams",
+        verbose_name=_("Lesson"),
+    )
 
     date = models.DateField(verbose_name=_("Date of exam"), null=True)
-    period_from = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("Start period"), null=True, related_name="+")
-    period_to = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("End period"), null=True, related_name="+")
+    period_from = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("Start period"),
+        null=True,
+        related_name="+",
+    )
+    period_to = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("End period"),
+        null=True,
+        related_name="+",
+    )
 
     title = models.CharField(verbose_name=_("Title"), max_length=255)
     comment = models.TextField(verbose_name=_("Comment"), blank=True, null=True)
@@ -476,12 +599,22 @@ class Break(ExtensibleModel):
     short_name = models.CharField(verbose_name=_("Short name"), max_length=255)
     name = models.CharField(verbose_name=_("Long name"), max_length=255)
 
-    after_period = models.ForeignKey("TimePeriod", on_delete=models.CASCADE,
-                                    verbose_name=_("Time period after break starts"),
-                                    related_name="break_after", blank=True, null=True)
-    before_period = models.ForeignKey("TimePeriod", on_delete=models.CASCADE,
-                                  verbose_name=_("Time period before break ends"),
-                                  related_name="break_before", blank=True, null=True)
+    after_period = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("Time period after break starts"),
+        related_name="break_after",
+        blank=True,
+        null=True,
+    )
+    before_period = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("Time period before break ends"),
+        related_name="break_before",
+        blank=True,
+        null=True,
+    )
 
     @property
     def weekday(self):
@@ -536,9 +669,21 @@ class Break(ExtensibleModel):
 class Supervision(ExtensibleModel):
     objects = models.Manager.from_queryset(SupervisionQuerySet)()
 
-    area = models.ForeignKey(SupervisionArea, models.CASCADE, verbose_name=_("Supervision area"), related_name="supervisions")
-    break_item = models.ForeignKey(Break, models.CASCADE, verbose_name=_("Break"), related_name="supervisions")
-    teacher = models.ForeignKey("core.Person", models.CASCADE, related_name="supervisions", verbose_name=_("Teacher"))
+    area = models.ForeignKey(
+        SupervisionArea,
+        models.CASCADE,
+        verbose_name=_("Supervision area"),
+        related_name="supervisions",
+    )
+    break_item = models.ForeignKey(
+        Break, models.CASCADE, verbose_name=_("Break"), related_name="supervisions"
+    )
+    teacher = models.ForeignKey(
+        "core.Person",
+        models.CASCADE,
+        related_name="supervisions",
+        verbose_name=_("Teacher"),
+    )
 
     def get_substitution(
         self, week: Optional[int] = None
@@ -563,14 +708,24 @@ class Supervision(ExtensibleModel):
 
     class Meta:
         ordering = ["area", "break_item"]
-        verbose_name= _("Supervision")
+        verbose_name = _("Supervision")
         verbose_name_plural = _("Supervisions")
 
 
 class SupervisionSubstitution(ExtensibleModel):
     date = models.DateField(verbose_name=_("Date"))
-    supervision = models.ForeignKey(Supervision, models.CASCADE, verbose_name=_("Supervision"), related_name="substitutions")
-    teacher = models.ForeignKey("core.Person", models.CASCADE, related_name="substituted_supervisions", verbose_name=_("Teacher"))
+    supervision = models.ForeignKey(
+        Supervision,
+        models.CASCADE,
+        verbose_name=_("Supervision"),
+        related_name="substitutions",
+    )
+    teacher = models.ForeignKey(
+        "core.Person",
+        models.CASCADE,
+        related_name="substituted_supervisions",
+        verbose_name=_("Teacher"),
+    )
 
     @property
     def teachers(self):
@@ -590,17 +745,35 @@ class Event(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
 
     objects = models.Manager.from_queryset(EventQuerySet)()
 
-    title = models.CharField(verbose_name=_("Title"), max_length=255, blank=True, null=True)
+    title = models.CharField(
+        verbose_name=_("Title"), max_length=255, blank=True, null=True
+    )
 
     date_start = models.DateField(verbose_name=_("Start date"), null=True)
     date_end = models.DateField(verbose_name=_("End date"), null=True)
 
-    period_from = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("Start time period"), related_name="+")
-    period_to = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("End time period"), related_name="+")
+    period_from = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("Start time period"),
+        related_name="+",
+    )
+    period_to = models.ForeignKey(
+        "TimePeriod",
+        on_delete=models.CASCADE,
+        verbose_name=_("End time period"),
+        related_name="+",
+    )
 
-    groups = models.ManyToManyField("core.Group", related_name="events", verbose_name=_("Groups"))
-    rooms = models.ManyToManyField("Room", related_name="events", verbose_name=_("Rooms"))
-    teachers = models.ManyToManyField("core.Person", related_name="events", verbose_name=_("Teachers"))
+    groups = models.ManyToManyField(
+        "core.Group", related_name="events", verbose_name=_("Groups")
+    )
+    rooms = models.ManyToManyField(
+        "Room", related_name="events", verbose_name=_("Rooms")
+    )
+    teachers = models.ManyToManyField(
+        "core.Person", related_name="events", verbose_name=_("Teachers")
+    )
 
     def __str__(self):
         if self.title:
@@ -626,7 +799,9 @@ class Event(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
 
     class Meta:
         ordering = ["date_start"]
-        indexes = [models.Index(fields=["period_from", "period_to", "date_start", "date_end"])]
+        indexes = [
+            models.Index(fields=["period_from", "period_to", "date_start", "date_end"])
+        ]
         verbose_name = _("Event")
         verbose_name_plural = _("Events")
 
@@ -636,15 +811,41 @@ class ExtraLesson(ExtensibleModel, GroupPropertiesMixin):
 
     objects = models.Manager.from_queryset(ExtraLessonQuerySet)()
 
-    week = models.IntegerField(verbose_name=_("Week"), default=CalendarWeek.current_week)
-    period = models.ForeignKey("TimePeriod", models.CASCADE, related_name="extra_lessons", verbose_name=_("Time period"))
+    week = models.IntegerField(
+        verbose_name=_("Week"), default=CalendarWeek.current_week
+    )
+    period = models.ForeignKey(
+        "TimePeriod",
+        models.CASCADE,
+        related_name="extra_lessons",
+        verbose_name=_("Time period"),
+    )
 
-    subject = models.ForeignKey("Subject", on_delete=models.CASCADE, related_name="extra_lessons", verbose_name=_("Subject"))
-    groups = models.ManyToManyField("core.Group", related_name="extra_lessons", verbose_name=_("Groups"))
-    teachers = models.ManyToManyField("core.Person", related_name="extra_lessons_as_teacher", verbose_name=_("Teachers"))
-    room = models.ForeignKey("Room", models.CASCADE, null=True, related_name="extra_lessons", verbose_name=_("Room"))
+    subject = models.ForeignKey(
+        "Subject",
+        on_delete=models.CASCADE,
+        related_name="extra_lessons",
+        verbose_name=_("Subject"),
+    )
+    groups = models.ManyToManyField(
+        "core.Group", related_name="extra_lessons", verbose_name=_("Groups")
+    )
+    teachers = models.ManyToManyField(
+        "core.Person",
+        related_name="extra_lessons_as_teacher",
+        verbose_name=_("Teachers"),
+    )
+    room = models.ForeignKey(
+        "Room",
+        models.CASCADE,
+        null=True,
+        related_name="extra_lessons",
+        verbose_name=_("Room"),
+    )
 
-    comment = models.CharField(verbose_name=_("Comment"), blank=True, null=True, max_length=255)
+    comment = models.CharField(
+        verbose_name=_("Comment"), blank=True, null=True, max_length=255
+    )
 
     def __str__(self):
         return "{}, {}, {}".format(self.week, self.period, self.subject)
diff --git a/aleksis/apps/chronos/preferences.py b/aleksis/apps/chronos/preferences.py
index 69b435a4..c0a4294d 100644
--- a/aleksis/apps/chronos/preferences.py
+++ b/aleksis/apps/chronos/preferences.py
@@ -3,7 +3,10 @@ from django.utils.translation import gettext as _
 from dynamic_preferences.preferences import Section
 from dynamic_preferences.types import BooleanPreference, IntegerPreference
 
-from aleksis.core.registries import site_preferences_registry, person_preferences_registry
+from aleksis.core.registries import (
+    site_preferences_registry,
+    person_preferences_registry,
+)
 
 chronos = Section("chronos", verbose_name=_("Chronos"))
 
@@ -50,10 +53,11 @@ class SubstitutionsPrintNumberOfDays(IntegerPreference):
     default = 2
     verbose_name = _("Number of days shown on substitutions print view")
 
+
 @site_preferences_registry.register
 class SubstitutionsShowHeaderBox(BooleanPreference):
     section = chronos
     name = "substitutions_show_header_box"
     default = True
     verbose_name = _("Show header box in substitution views")
-    help_text =  _("The header box shows affected teachers/groups.")
+    help_text = _("The header box shows affected teachers/groups.")
diff --git a/aleksis/apps/chronos/rules.py b/aleksis/apps/chronos/rules.py
index ddc398cd..dc0369b0 100644
--- a/aleksis/apps/chronos/rules.py
+++ b/aleksis/apps/chronos/rules.py
@@ -7,12 +7,12 @@ from aleksis.core.util.predicates import (
     has_object_perm,
 )
 from .models import LessonSubstitution
-from .util.predicates import (
-    has_timetable_perm
-)
+from .util.predicates import has_timetable_perm
 
 # View timetable overview
-view_timetable_overview_predicate = has_person & has_global_perm("chronos.view_timetable_overview")
+view_timetable_overview_predicate = has_person & has_global_perm(
+    "chronos.view_timetable_overview"
+)
 add_perm("chronos.view_timetable_overview", view_timetable_overview_predicate)
 
 # View my timetable
@@ -30,18 +30,21 @@ add_perm("chronos.view_lessons_day", view_lessons_day_predicate)
 
 # Edit substition
 edit_substitution_predicate = has_person & (
-    has_global_perm("chronos.change_lessonsubstitution") | has_object_perm("chronos.change_lessonsubstitution")
+    has_global_perm("chronos.change_lessonsubstitution")
+    | has_object_perm("chronos.change_lessonsubstitution")
 )
 add_perm("chronos.edit_substitution", edit_substitution_predicate)
 
 # Delete substitution
 delete_substitution_predicate = has_person & (
-    has_global_perm("chronos.delete_lessonsubstitution") | has_object_perm("chronos.delete_lessonsubstitution")
+    has_global_perm("chronos.delete_lessonsubstitution")
+    | has_object_perm("chronos.delete_lessonsubstitution")
 )
 add_perm("chronos.delete_substitution", delete_substitution_predicate)
 
 # View substitutions
 view_substitutions_predicate = has_person & (
-    has_global_perm("chronos.view_lessonsubstitution") | has_any_object("chronos.view_lessonsubstitution", LessonSubstitution)
+    has_global_perm("chronos.view_lessonsubstitution")
+    | has_any_object("chronos.view_lessonsubstitution", LessonSubstitution)
 )
 add_perm("chronos.view_substitutions", view_substitutions_predicate)
diff --git a/aleksis/apps/chronos/tables.py b/aleksis/apps/chronos/tables.py
index 9915dd47..92a966fe 100644
--- a/aleksis/apps/chronos/tables.py
+++ b/aleksis/apps/chronos/tables.py
@@ -25,16 +25,24 @@ def _css_class_from_lesson_state(
 
 class LessonsTable(tables.Table):
     """Table for daily lessons and management of substitutions."""
+
     class Meta:
         attrs = {"class": "highlight"}
         row_attrs = {"class": _css_class_from_lesson_state}
 
     period__period = tables.Column(accessor="period__period")
-    lesson__groups = tables.Column(accessor="lesson__group_names", verbose_name=_("Groups"))
-    lesson__teachers = tables.Column(accessor="lesson__teacher_names", verbose_name=_("Teachers"))
+    lesson__groups = tables.Column(
+        accessor="lesson__group_names", verbose_name=_("Groups")
+    )
+    lesson__teachers = tables.Column(
+        accessor="lesson__teacher_names", verbose_name=_("Teachers")
+    )
     lesson__subject = tables.Column(accessor="lesson__subject")
     room = tables.Column(accessor="room")
     edit_substitution = tables.LinkColumn(
-        "edit_substitution", args=[A("id"), A("_week")], text=_("Substitution"),
-        attrs={"a": {"class": "btn-flat waves-effect waves-orange"}}, verbose_name=_("Manage substitution")
+        "edit_substitution",
+        args=[A("id"), A("_week")],
+        text=_("Substitution"),
+        attrs={"a": {"class": "btn-flat waves-effect waves-orange"}},
+        verbose_name=_("Manage substitution"),
     )
diff --git a/aleksis/apps/chronos/templatetags/common.py b/aleksis/apps/chronos/templatetags/common.py
index 2a33c1b0..cfdec15c 100644
--- a/aleksis/apps/chronos/templatetags/common.py
+++ b/aleksis/apps/chronos/templatetags/common.py
@@ -4,7 +4,6 @@ register = template.Library()
 
 
 class SetVarNode(template.Node):
-
     def __init__(self, var_name, var_value):
         self.var_name = var_name
         self.var_value = var_value
@@ -19,13 +18,15 @@ class SetVarNode(template.Node):
         return u""
 
 
-@register.tag(name='set')
+@register.tag(name="set")
 def set_var(parser, token):
     """
     {% set some_var = '123' %}
     """
     parts = token.split_contents()
     if len(parts) < 4:
-        raise template.TemplateSyntaxError("'set' tag must be of the form: {% set <var_name> = <var_value> %}")
+        raise template.TemplateSyntaxError(
+            "'set' tag must be of the form: {% set <var_name> = <var_value> %}"
+        )
 
     return SetVarNode(parts[1], parts[3])
diff --git a/aleksis/apps/chronos/templatetags/week_helpers.py b/aleksis/apps/chronos/templatetags/week_helpers.py
index acfb3a3a..054d3f9e 100644
--- a/aleksis/apps/chronos/templatetags/week_helpers.py
+++ b/aleksis/apps/chronos/templatetags/week_helpers.py
@@ -4,7 +4,11 @@ from typing import Optional, Union
 from django import template
 from django.db.models.query import QuerySet
 
-from aleksis.apps.chronos.util.date import CalendarWeek, week_period_to_date, week_weekday_to_date
+from aleksis.apps.chronos.util.date import (
+    CalendarWeek,
+    week_period_to_date,
+    week_weekday_to_date,
+)
 
 register = template.Library()
 
diff --git a/aleksis/apps/chronos/urls.py b/aleksis/apps/chronos/urls.py
index d5311f49..3d68c3a1 100644
--- a/aleksis/apps/chronos/urls.py
+++ b/aleksis/apps/chronos/urls.py
@@ -5,12 +5,28 @@ from . import views
 urlpatterns = [
     path("", views.all_timetables, name="all_timetables"),
     path("timetable/my/", views.my_timetable, name="my_timetable"),
-    path("timetable/my/<int:year>/<int:month>/<int:day>/", views.my_timetable, name="my_timetable_by_date"),
+    path(
+        "timetable/my/<int:year>/<int:month>/<int:day>/",
+        views.my_timetable,
+        name="my_timetable_by_date",
+    ),
     path("timetable/<str:type_>/<int:pk>/", views.timetable, name="timetable"),
-    path("timetable/<str:type_>/<int:pk>/<int:year>/<int:week>/", views.timetable, name="timetable_by_week"),
-    path("timetable/<str:type_>/<int:pk>/<str:regular>/", views.timetable, name="timetable_regular"),
+    path(
+        "timetable/<str:type_>/<int:pk>/<int:year>/<int:week>/",
+        views.timetable,
+        name="timetable_by_week",
+    ),
+    path(
+        "timetable/<str:type_>/<int:pk>/<str:regular>/",
+        views.timetable,
+        name="timetable_regular",
+    ),
     path("lessons/", views.lessons_day, name="lessons_day"),
-    path("lessons/<int:year>/<int:month>/<int:day>/", views.lessons_day, name="lessons_day_by_date"),
+    path(
+        "lessons/<int:year>/<int:month>/<int:day>/",
+        views.lessons_day,
+        name="lessons_day_by_date",
+    ),
     path(
         "lessons/<int:id_>/<int:week>/substition/",
         views.edit_substitution,
@@ -22,7 +38,21 @@ urlpatterns = [
         name="delete_substitution",
     ),
     path("substitutions/", views.substitutions, name="substitutions"),
-    path("substitutions/print/", views.substitutions, {"is_print": True}, name="substitutions_print"),
-    path("substitutions/<int:year>/<int:month>/<int:day>/", views.substitutions, name="substitutions_by_date"),
-    path("substitutions/<int:year>/<int:month>/<int:day>/print/", views.substitutions, {"is_print": True}, name="substitutions_print_by_date"),
+    path(
+        "substitutions/print/",
+        views.substitutions,
+        {"is_print": True},
+        name="substitutions_print",
+    ),
+    path(
+        "substitutions/<int:year>/<int:month>/<int:day>/",
+        views.substitutions,
+        name="substitutions_by_date",
+    ),
+    path(
+        "substitutions/<int:year>/<int:month>/<int:day>/print/",
+        views.substitutions,
+        {"is_print": True},
+        name="substitutions_print_by_date",
+    ),
 ]
diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py
index 9fbc4ce5..a73798e9 100644
--- a/aleksis/apps/chronos/util/build.py
+++ b/aleksis/apps/chronos/util/build.py
@@ -21,7 +21,9 @@ ExtraLesson = apps.get_model("chronos", "ExtraLesson")
 
 
 def build_timetable(
-    type_: Union[TimetableType, str], obj: Union[int, Person], date_ref: Union[CalendarWeek, date]
+    type_: Union[TimetableType, str],
+    obj: Union[int, Person],
+    date_ref: Union[CalendarWeek, date],
 ):
     needed_breaks = []
 
@@ -59,7 +61,9 @@ def build_timetable(
     if is_person:
         extra_lessons = ExtraLesson.objects.on_day(date_ref).filter_from_person(obj)
     else:
-        extra_lessons = ExtraLesson.objects.filter(week=date_ref.week).filter_from_type(type_, obj)
+        extra_lessons = ExtraLesson.objects.filter(week=date_ref.week).filter_from_type(
+            type_, obj
+        )
 
     # Sort lesson periods in a dict
     extra_lessons_per_period = extra_lessons.group_by_periods(is_person=is_person)
@@ -108,7 +112,7 @@ def build_timetable(
                 # If not end day, use max period
                 period_to = TimePeriod.period_max
 
-            for period in range(period_from, period_to +1):
+            for period in range(period_from, period_to + 1):
                 if period not in events_per_period:
                     events_per_period[period] = [] if is_person else {}
 
@@ -126,7 +130,9 @@ def build_timetable(
             week = CalendarWeek.from_date(date_ref)
         else:
             week = date_ref
-        supervisions = Supervision.objects.all().annotate_week(week).filter_by_teacher(obj)
+        supervisions = (
+            Supervision.objects.all().annotate_week(week).filter_by_teacher(obj)
+        )
 
         if is_person:
             supervisions.filter_by_weekday(date_ref.weekday())
@@ -280,7 +286,7 @@ def build_substitutions_list(wanted_day: date) -> List[dict]:
             "type": "supervision_substitution",
             "sort_a": "Z.{}".format(super_sub.teacher),
             "sort_b": "{}".format(super_sub.supervision.break_item.after_period_number),
-            "el": super_sub
+            "el": super_sub,
         }
         rows.append(row)
 
diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py
index 72821e75..532d0ed9 100644
--- a/aleksis/apps/chronos/views.py
+++ b/aleksis/apps/chronos/views.py
@@ -64,7 +64,9 @@ def my_timetable(
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
         wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(
+            timezone.now().date(), datetime.now().time()
+        )
 
     if has_person(request.user):
         person = request.user.person
@@ -86,7 +88,9 @@ def my_timetable(
         context["day"] = wanted_day
         context["periods"] = TimePeriod.get_times_dict()
         context["smart"] = True
-        context["announcements"] = Announcement.for_timetables().on_date(wanted_day).for_person(person)
+        context["announcements"] = (
+            Announcement.for_timetables().on_date(wanted_day).for_person(person)
+        )
 
         context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
             wanted_day, "my_timetable_by_date"
@@ -148,7 +152,9 @@ def timetable(
 
     # Build lists with weekdays and corresponding dates (long and short variant)
     context["weekdays"] = build_weekdays(TimePeriod.WEEKDAY_CHOICES, wanted_week)
-    context["weekdays_short"] = build_weekdays(TimePeriod.WEEKDAY_CHOICES_SHORT, wanted_week)
+    context["weekdays_short"] = build_weekdays(
+        TimePeriod.WEEKDAY_CHOICES_SHORT, wanted_week
+    )
 
     context["weeks"] = get_weeks_for_year(year=wanted_week.year)
     context["week"] = wanted_week
@@ -158,13 +164,15 @@ def timetable(
     context["smart"] = is_smart
     context["week_select"] = {
         "year": wanted_week.year,
-        "dest": reverse("timetable", args=[type_, pk])
+        "dest": reverse("timetable", args=[type_, pk]),
     }
 
     if is_smart:
         start = wanted_week[TimePeriod.weekday_min]
         stop = wanted_week[TimePeriod.weekday_max]
-        context["announcements"] = Announcement.for_timetables().relevant_for(el).within_days(start, stop)
+        context["announcements"] = (
+            Announcement.for_timetables().relevant_for(el).within_days(start, stop)
+        )
 
     week_prev = wanted_week - 1
     week_next = wanted_week + 1
@@ -193,7 +201,9 @@ def lessons_day(
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
         wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(
+            timezone.now().date(), datetime.now().time()
+        )
 
     # Get lessons
     lesson_periods = LessonPeriod.objects.on_day(wanted_day)
@@ -208,7 +218,7 @@ def lessons_day(
 
     context["datepicker"] = {
         "date": date_unix(wanted_day),
-        "dest": reverse("lessons_day")
+        "dest": reverse("lessons_day"),
     }
 
     context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
@@ -257,8 +267,7 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
 
             date = wanted_week[lesson_period.period.weekday]
             return redirect(
-                "lessons_day_by_date",
-                year=date.year, month=date.month, day=date.day
+                "lessons_day_by_date", year=date.year, month=date.month, day=date.day
             )
 
     context["edit_substitution_form"] = edit_substitution_form
@@ -281,8 +290,7 @@ def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpRespon
 
     date = wanted_week[lesson_period.period.weekday]
     return redirect(
-        "lessons_day_by_date",
-        year=date.year, month=date.month, day=date.day
+        "lessons_day_by_date", year=date.year, month=date.month, day=date.day
     )
 
 
@@ -301,7 +309,9 @@ def substitutions(
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
         wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(
+            timezone.now().date(), datetime.now().time()
+        )
 
     day_number = get_site_preferences()["chronos__substitutions_print_number_of_days"]
     day_contexts = {}
@@ -318,11 +328,14 @@ def substitutions(
         subs = build_substitutions_list(day)
         day_contexts[day]["substitutions"] = subs
 
-        day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day).filter(show_in_timetables=True)
+        day_contexts[day]["announcements"] = (
+            Announcement.for_timetables().on_date(day).filter(show_in_timetables=True)
+        )
 
         if get_site_preferences()["chronos__substitutions_show_header_box"]:
-            subs = LessonSubstitution.objects.on_day(day).order_by("lesson_period__lesson__groups",
-                                                                   "lesson_period__period")
+            subs = LessonSubstitution.objects.on_day(day).order_by(
+                "lesson_period__lesson__groups", "lesson_period__period"
+            )
             absences = Absence.objects.on_day(day)
             day_contexts[day]["absent_teachers"] = absences.absent_teachers()
             day_contexts[day]["absent_groups"] = absences.absent_groups()
-- 
GitLab