diff --git a/aleksis/apps/chronos/forms.py b/aleksis/apps/chronos/forms.py
index 3233cf8915326860c3d5370915c5ae37bd059a08..5b4803d7622844c7a29cdc6b7fb0f456adc3c316 100644
--- a/aleksis/apps/chronos/forms.py
+++ b/aleksis/apps/chronos/forms.py
@@ -26,4 +26,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 361f8da29cdeecf23ff80fc14ea722f9623d52c1..b78d2d2a0d4355f37441bd7d97b897833d892bbc 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -69,7 +69,7 @@ class WeekQuerySetMixin:
 
         return self.annotate(
             _week=models.Value(week.week, models.IntegerField()),
-            _year=models.Value(week.year, models.IntegerField())
+            _year=models.Value(week.year, models.IntegerField()),
         )
 
 
@@ -116,8 +116,10 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
     def in_week(self, wanted_week: CalendarWeek):
         """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):
@@ -149,7 +151,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
         """Filter for all lessons a participant (student) attends."""
         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]):
@@ -170,7 +174,10 @@ 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"),}
+            **{
+                self._subst_path + "teachers": teacher,
+                self._subst_path + "week": F("_week"),
+            }
         )
 
         return qs1.union(qs2)
@@ -184,7 +191,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
 
         return qs1.union(qs2)
 
-    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:
             return self.filter_group(pk)
@@ -224,7 +233,9 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
 
         return lesson_periods
 
-    def next_lesson(self, reference: "LessonPeriod", offset: Optional[int] = 1) -> "LessonPeriod":
+    def next_lesson(
+        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,
@@ -272,7 +283,8 @@ class LessonSubstitutionQuerySet(LessonDataQuerySet):
         selected substitutions (as substituted or substituting).
         """
         return Person.objects.filter(
-            Q(lessons_as_teacher__in=self.affected_lessons()) | Q(lesson_substitutions__in=self)
+            Q(lessons_as_teacher__in=self.affected_lessons())
+            | Q(lesson_substitutions__in=self)
         ).annotate(lessons_count=Count("lessons_as_teacher"))
 
     def affected_groups(self):
@@ -313,13 +325,19 @@ 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):
@@ -393,7 +411,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:
             return self.filter_group(pk)
diff --git a/aleksis/apps/chronos/migrations/0001_initial.py b/aleksis/apps/chronos/migrations/0001_initial.py
index c27756636c30241178c68a29512b67bf8849b826..c1842ed902696312eca6b51a1bdbfaf5a71cbc8c 100644
--- a/aleksis/apps/chronos/migrations/0001_initial.py
+++ b/aleksis/apps/chronos/migrations/0001_initial.py
@@ -1,12 +1,14 @@
 # Generated by Django 3.0.5 on 2020-05-04 14:16
 
-import aleksis.apps.chronos.managers
-import calendarweek.calendarweek
-import colorfield.fields
 import django.contrib.postgres.fields.jsonb
 import django.contrib.sites.managers
-from django.db import migrations, models
 import django.db.models.deletion
+from django.db import migrations, models
+
+import calendarweek.calendarweek
+import colorfield.fields
+
+import aleksis.apps.chronos.managers
 
 
 class Migration(migrations.Migration):
@@ -14,449 +16,1188 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('core', '0001_initial'),
-        ('sites', '0002_alter_domain_unique'),
+        ("core", "0001_initial"),
+        ("sites", "0002_alter_domain_unique"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='ChronosGlobalPermissions',
+            name="ChronosGlobalPermissions",
             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,
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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=255, verbose_name='Short name')),
-                ('name', models.CharField(max_length=255, verbose_name='Long name')),
+                (
+                    "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=255, verbose_name="Short name"),
+                ),
+                ("name", models.CharField(max_length=255, verbose_name="Long name")),
             ],
             options={
-                'verbose_name': 'Break',
-                'verbose_name_plural': 'Breaks',
-                'ordering': ['after_period'],
+                "verbose_name": "Break",
+                "verbose_name_plural": "Breaks",
+                "ordering": ["after_period"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         migrations.CreateModel(
-            name='Lesson',
+            name="Lesson",
             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='Start date')),
-                ('date_end', models.DateField(null=True, verbose_name='End date')),
-                ('groups', models.ManyToManyField(related_name='lessons', to='core.Group', verbose_name='Groups')),
+                (
+                    "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="Start date")),
+                ("date_end", models.DateField(null=True, verbose_name="End date")),
+                (
+                    "groups",
+                    models.ManyToManyField(
+                        related_name="lessons", to="core.Group", verbose_name="Groups"
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Lesson',
-                'verbose_name_plural': 'Lessons',
-                'ordering': ['date_start', 'subject'],
+                "verbose_name": "Lesson",
+                "verbose_name_plural": "Lessons",
+                "ordering": ["date_start", "subject"],
             },
-            bases=(models.Model, aleksis.apps.chronos.managers.GroupPropertiesMixin, aleksis.apps.chronos.managers.TeacherPropertiesMixin),
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            bases=(
+                models.Model,
+                aleksis.apps.chronos.managers.GroupPropertiesMixin,
+                aleksis.apps.chronos.managers.TeacherPropertiesMixin,
+            ),
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         migrations.CreateModel(
-            name='LessonPeriod',
+            name="LessonPeriod",
             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)),
-                ('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lesson_periods', to='chronos.Lesson', verbose_name='Lesson')),
+                (
+                    "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
+                    ),
+                ),
+                (
+                    "lesson",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="lesson_periods",
+                        to="chronos.Lesson",
+                        verbose_name="Lesson",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Lesson period',
-                'verbose_name_plural': 'Lesson periods',
-                'ordering': ['lesson__date_start', 'period__weekday', 'period__period', 'lesson__subject'],
+                "verbose_name": "Lesson period",
+                "verbose_name_plural": "Lesson periods",
+                "ordering": [
+                    "lesson__date_start",
+                    "period__weekday",
+                    "period__period",
+                    "lesson__subject",
+                ],
             },
         ),
         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='TimetableWidget',
-            fields=[
-            ],
+            name="TimetableWidget",
+            fields=[],
             options={
-                'verbose_name': 'Timetable widget',
-                'verbose_name_plural': 'Timetable widgets',
-                'proxy': True,
-                'indexes': [],
-                'constraints': [],
+                "verbose_name": "Timetable widget",
+                "verbose_name_plural": "Timetable widgets",
+                "proxy": True,
+                "indexes": [],
+                "constraints": [],
             },
-            bases=('core.dashboardwidget',),
+            bases=("core.dashboardwidget",),
         ),
         migrations.CreateModel(
-            name='TimePeriod',
+            name="TimePeriod",
             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)),
-                ('weekday', models.PositiveSmallIntegerField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], verbose_name='Week day')),
-                ('period', models.PositiveSmallIntegerField(verbose_name='Number of period')),
-                ('time_start', models.TimeField(verbose_name='Start time')),
-                ('time_end', models.TimeField(verbose_name='End time')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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
+                    ),
+                ),
+                (
+                    "weekday",
+                    models.PositiveSmallIntegerField(
+                        choices=[
+                            (0, "Monday"),
+                            (1, "Tuesday"),
+                            (2, "Wednesday"),
+                            (3, "Thursday"),
+                            (4, "Friday"),
+                            (5, "Saturday"),
+                            (6, "Sunday"),
+                        ],
+                        verbose_name="Week day",
+                    ),
+                ),
+                (
+                    "period",
+                    models.PositiveSmallIntegerField(verbose_name="Number of period"),
+                ),
+                ("time_start", models.TimeField(verbose_name="Start time")),
+                ("time_end", models.TimeField(verbose_name="End time")),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Time period',
-                'verbose_name_plural': 'Time periods',
-                'ordering': ['weekday', 'period'],
+                "verbose_name": "Time period",
+                "verbose_name_plural": "Time periods",
+                "ordering": ["weekday", "period"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
-                ('supervision', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='substitutions', to='chronos.Supervision', verbose_name='Supervision')),
-                ('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='substituted_supervisions', to='core.Person', verbose_name='Teacher')),
+                (
+                    "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")),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
+                (
+                    "supervision",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="substitutions",
+                        to="chronos.Supervision",
+                        verbose_name="Supervision",
+                    ),
+                ),
+                (
+                    "teacher",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="substituted_supervisions",
+                        to="core.Person",
+                        verbose_name="Teacher",
+                    ),
+                ),
             ],
             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"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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=255, verbose_name='Short name')),
-                ('name', models.CharField(max_length=255, verbose_name='Long name')),
-                ('colour_fg', colorfield.fields.ColorField(default='#000000', max_length=18)),
-                ('colour_bg', colorfield.fields.ColorField(default='#FFFFFF', max_length=18)),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, verbose_name="Short name"),
+                ),
+                ("name", models.CharField(max_length=255, verbose_name="Long name")),
+                (
+                    "colour_fg",
+                    colorfield.fields.ColorField(default="#000000", max_length=18),
+                ),
+                (
+                    "colour_bg",
+                    colorfield.fields.ColorField(default="#FFFFFF", max_length=18),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Supervision area',
-                'verbose_name_plural': 'Supervision areas',
-                'ordering': ['name'],
+                "verbose_name": "Supervision area",
+                "verbose_name_plural": "Supervision areas",
+                "ordering": ["name"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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='site',
-            field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site'),
+            model_name="supervision",
+            name="site",
+            field=models.ForeignKey(
+                default=1,
+                editable=False,
+                on_delete=django.db.models.deletion.CASCADE,
+                to="sites.Site",
+            ),
         ),
         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.CreateModel(
-            name='Subject',
+            name="Subject",
             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=255, unique=True, verbose_name='Short name')),
-                ('name', models.CharField(max_length=255, unique=True, verbose_name='Long name')),
-                ('colour_fg', colorfield.fields.ColorField(blank=True, default='', max_length=18, verbose_name='Foreground colour')),
-                ('colour_bg', colorfield.fields.ColorField(blank=True, default='', max_length=18, verbose_name='Background colour')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, unique=True, verbose_name="Short name"
+                    ),
+                ),
+                (
+                    "name",
+                    models.CharField(
+                        max_length=255, unique=True, verbose_name="Long name"
+                    ),
+                ),
+                (
+                    "colour_fg",
+                    colorfield.fields.ColorField(
+                        blank=True,
+                        default="",
+                        max_length=18,
+                        verbose_name="Foreground colour",
+                    ),
+                ),
+                (
+                    "colour_bg",
+                    colorfield.fields.ColorField(
+                        blank=True,
+                        default="",
+                        max_length=18,
+                        verbose_name="Background colour",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Subject',
-                'verbose_name_plural': 'Subjects',
-                'ordering': ['name', 'short_name'],
+                "verbose_name": "Subject",
+                "verbose_name_plural": "Subjects",
+                "ordering": ["name", "short_name"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         migrations.CreateModel(
-            name='Room',
+            name="Room",
             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=255, unique=True, verbose_name='Short name')),
-                ('name', models.CharField(max_length=255, verbose_name='Long name')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, unique=True, verbose_name="Short name"
+                    ),
+                ),
+                ("name", models.CharField(max_length=255, verbose_name="Long name")),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Room',
-                'verbose_name_plural': 'Rooms',
-                'ordering': ['name', 'short_name'],
+                "verbose_name": "Room",
+                "verbose_name_plural": "Rooms",
+                "ordering": ["name", "short_name"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         migrations.CreateModel(
-            name='LessonSubstitution',
+            name="LessonSubstitution",
             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')),
-                ('cancelled', models.BooleanField(default=False, verbose_name='Cancelled?')),
-                ('cancelled_for_teachers', models.BooleanField(default=False, verbose_name='Cancelled for teachers?')),
-                ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')),
-                ('lesson_period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='substitutions', to='chronos.LessonPeriod', verbose_name='Lesson period')),
-                ('room', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='chronos.Room', verbose_name='Room')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
-                ('subject', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='lesson_substitutions', to='chronos.Subject', verbose_name='Subject')),
-                ('teachers', models.ManyToManyField(blank=True, related_name='lesson_substitutions', to='core.Person', verbose_name='Teachers')),
+                (
+                    "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",
+                    ),
+                ),
+                (
+                    "cancelled",
+                    models.BooleanField(default=False, verbose_name="Cancelled?"),
+                ),
+                (
+                    "cancelled_for_teachers",
+                    models.BooleanField(
+                        default=False, verbose_name="Cancelled for teachers?"
+                    ),
+                ),
+                (
+                    "comment",
+                    models.TextField(blank=True, null=True, verbose_name="Comment"),
+                ),
+                (
+                    "lesson_period",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="substitutions",
+                        to="chronos.LessonPeriod",
+                        verbose_name="Lesson period",
+                    ),
+                ),
+                (
+                    "room",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="chronos.Room",
+                        verbose_name="Room",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
+                (
+                    "subject",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="lesson_substitutions",
+                        to="chronos.Subject",
+                        verbose_name="Subject",
+                    ),
+                ),
+                (
+                    "teachers",
+                    models.ManyToManyField(
+                        blank=True,
+                        related_name="lesson_substitutions",
+                        to="core.Person",
+                        verbose_name="Teachers",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Lesson substitution',
-                'verbose_name_plural': 'Lesson substitutions',
-                'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period'],
+                "verbose_name": "Lesson substitution",
+                "verbose_name_plural": "Lesson substitutions",
+                "ordering": [
+                    "lesson_period__lesson__date_start",
+                    "week",
+                    "lesson_period__period__weekday",
+                    "lesson_period__period__period",
+                ],
             },
         ),
         migrations.AddField(
-            model_name='lessonperiod',
-            name='period',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lesson_periods', to='chronos.TimePeriod', verbose_name='Time period'),
+            model_name="lessonperiod",
+            name="period",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="lesson_periods",
+                to="chronos.TimePeriod",
+                verbose_name="Time period",
+            ),
         ),
         migrations.AddField(
-            model_name='lessonperiod',
-            name='room',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='lesson_periods', to='chronos.Room', verbose_name='Room'),
+            model_name="lessonperiod",
+            name="room",
+            field=models.ForeignKey(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="lesson_periods",
+                to="chronos.Room",
+                verbose_name="Room",
+            ),
         ),
         migrations.AddField(
-            model_name='lessonperiod',
-            name='site',
-            field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site'),
+            model_name="lessonperiod",
+            name="site",
+            field=models.ForeignKey(
+                default=1,
+                editable=False,
+                on_delete=django.db.models.deletion.CASCADE,
+                to="sites.Site",
+            ),
         ),
         migrations.AddField(
-            model_name='lesson',
-            name='periods',
-            field=models.ManyToManyField(related_name='lessons', through='chronos.LessonPeriod', to='chronos.TimePeriod', verbose_name='Periods'),
+            model_name="lesson",
+            name="periods",
+            field=models.ManyToManyField(
+                related_name="lessons",
+                through="chronos.LessonPeriod",
+                to="chronos.TimePeriod",
+                verbose_name="Periods",
+            ),
         ),
         migrations.AddField(
-            model_name='lesson',
-            name='site',
-            field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site'),
+            model_name="lesson",
+            name="site",
+            field=models.ForeignKey(
+                default=1,
+                editable=False,
+                on_delete=django.db.models.deletion.CASCADE,
+                to="sites.Site",
+            ),
         ),
         migrations.AddField(
-            model_name='lesson',
-            name='subject',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lessons', to='chronos.Subject', verbose_name='Subject'),
+            model_name="lesson",
+            name="subject",
+            field=models.ForeignKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="lessons",
+                to="chronos.Subject",
+                verbose_name="Subject",
+            ),
         ),
         migrations.AddField(
-            model_name='lesson',
-            name='teachers',
-            field=models.ManyToManyField(related_name='lessons_as_teacher', to='core.Person', verbose_name='Teachers'),
+            model_name="lesson",
+            name="teachers",
+            field=models.ManyToManyField(
+                related_name="lessons_as_teacher",
+                to="core.Person",
+                verbose_name="Teachers",
+            ),
         ),
         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=255, verbose_name='Title')),
-                ('date_start', models.DateField(null=True, verbose_name='Start date')),
-                ('date_end', models.DateField(null=True, verbose_name='End date')),
-                ('comments', models.TextField(blank=True, null=True, verbose_name='Comments')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, verbose_name="Title")),
+                ("date_start", models.DateField(null=True, verbose_name="Start date")),
+                ("date_end", models.DateField(null=True, verbose_name="End date")),
+                (
+                    "comments",
+                    models.TextField(blank=True, null=True, verbose_name="Comments"),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Holiday',
-                'verbose_name_plural': 'Holidays',
-                'ordering': ['date_start'],
+                "verbose_name": "Holiday",
+                "verbose_name_plural": "Holidays",
+                "ordering": ["date_start"],
             },
         ),
         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')),
-                ('groups', models.ManyToManyField(related_name='extra_lessons', to='core.Group', verbose_name='Groups')),
-                ('period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.TimePeriod', verbose_name='Time period')),
-                ('room', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.Room', verbose_name='Room')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
-                ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extra_lessons', to='chronos.Subject', verbose_name='Subject')),
-                ('teachers', models.ManyToManyField(related_name='extra_lessons_as_teacher', to='core.Person', verbose_name='Teachers')),
+                (
+                    "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"
+                    ),
+                ),
+                (
+                    "groups",
+                    models.ManyToManyField(
+                        related_name="extra_lessons",
+                        to="core.Group",
+                        verbose_name="Groups",
+                    ),
+                ),
+                (
+                    "period",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="extra_lessons",
+                        to="chronos.TimePeriod",
+                        verbose_name="Time period",
+                    ),
+                ),
+                (
+                    "room",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="extra_lessons",
+                        to="chronos.Room",
+                        verbose_name="Room",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
+                (
+                    "subject",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="extra_lessons",
+                        to="chronos.Subject",
+                        verbose_name="Subject",
+                    ),
+                ),
+                (
+                    "teachers",
+                    models.ManyToManyField(
+                        related_name="extra_lessons_as_teacher",
+                        to="core.Person",
+                        verbose_name="Teachers",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Extra lesson',
-                'verbose_name_plural': 'Extra lessons',
+                "verbose_name": "Extra lesson",
+                "verbose_name_plural": "Extra lessons",
             },
             bases=(models.Model, aleksis.apps.chronos.managers.GroupPropertiesMixin),
         ),
         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=255, verbose_name='Title')),
-                ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')),
-                ('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exams', to='chronos.Lesson', verbose_name='Lesson')),
-                ('period_from', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Start period')),
-                ('period_to', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='End period')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, verbose_name="Title")),
+                (
+                    "comment",
+                    models.TextField(blank=True, null=True, verbose_name="Comment"),
+                ),
+                (
+                    "lesson",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="exams",
+                        to="chronos.Lesson",
+                        verbose_name="Lesson",
+                    ),
+                ),
+                (
+                    "period_from",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="Start period",
+                    ),
+                ),
+                (
+                    "period_to",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="End period",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Exam',
-                'verbose_name_plural': 'Exams',
-                'ordering': ['date'],
+                "verbose_name": "Exam",
+                "verbose_name_plural": "Exams",
+                "ordering": ["date"],
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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(blank=True, max_length=255, null=True, verbose_name='Title')),
-                ('date_start', models.DateField(null=True, verbose_name='Start date')),
-                ('date_end', models.DateField(null=True, verbose_name='End date')),
-                ('groups', models.ManyToManyField(related_name='events', to='core.Group', verbose_name='Groups')),
-                ('period_from', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Start time period')),
-                ('period_to', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='End time period')),
-                ('rooms', models.ManyToManyField(related_name='events', to='chronos.Room', verbose_name='Rooms')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
-                ('teachers', models.ManyToManyField(related_name='events', to='core.Person', verbose_name='Teachers')),
+                (
+                    "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(
+                        blank=True, max_length=255, null=True, verbose_name="Title"
+                    ),
+                ),
+                ("date_start", models.DateField(null=True, verbose_name="Start date")),
+                ("date_end", models.DateField(null=True, verbose_name="End date")),
+                (
+                    "groups",
+                    models.ManyToManyField(
+                        related_name="events", to="core.Group", verbose_name="Groups"
+                    ),
+                ),
+                (
+                    "period_from",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="Start time period",
+                    ),
+                ),
+                (
+                    "period_to",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="End time period",
+                    ),
+                ),
+                (
+                    "rooms",
+                    models.ManyToManyField(
+                        related_name="events", to="chronos.Room", verbose_name="Rooms"
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
+                (
+                    "teachers",
+                    models.ManyToManyField(
+                        related_name="events", to="core.Person", verbose_name="Teachers"
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Event',
-                'verbose_name_plural': 'Events',
-                'ordering': ['date_start'],
+                "verbose_name": "Event",
+                "verbose_name_plural": "Events",
+                "ordering": ["date_start"],
             },
-            bases=(models.Model, aleksis.apps.chronos.managers.GroupPropertiesMixin, aleksis.apps.chronos.managers.TeacherPropertiesMixin),
+            bases=(
+                models.Model,
+                aleksis.apps.chronos.managers.GroupPropertiesMixin,
+                aleksis.apps.chronos.managers.TeacherPropertiesMixin,
+            ),
         ),
         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='Time period after break starts'),
+            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="Time period after break starts",
+            ),
         ),
         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='Time period before break ends'),
+            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="Time period before break ends",
+            ),
         ),
         migrations.AddField(
-            model_name='break',
-            name='site',
-            field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site'),
+            model_name="break",
+            name="site",
+            field=models.ForeignKey(
+                default=1,
+                editable=False,
+                on_delete=django.db.models.deletion.CASCADE,
+                to="sites.Site",
+            ),
         ),
         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)),
-                ('short_name', models.CharField(max_length=255, verbose_name='Short name')),
-                ('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Name')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+                (
+                    "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=255, verbose_name="Short name"),
+                ),
+                (
+                    "name",
+                    models.CharField(
+                        blank=True, max_length=255, null=True, verbose_name="Name"
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Absence reason',
-                'verbose_name_plural': 'Absence reasons',
+                "verbose_name": "Absence reason",
+                "verbose_name_plural": "Absence reasons",
             },
-            managers=[
-                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
-            ],
+            managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
         ),
         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='Start date')),
-                ('date_end', models.DateField(null=True, verbose_name='End date')),
-                ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')),
-                ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Group', verbose_name='Group')),
-                ('period_from', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='Start period')),
-                ('period_to', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='chronos.TimePeriod', verbose_name='End period')),
-                ('reason', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='absences', to='chronos.AbsenceReason', verbose_name='Absence reason')),
-                ('room', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='chronos.Room', verbose_name='Room')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
-                ('teacher', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Person', verbose_name='Teacher')),
+                (
+                    "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="Start date")),
+                ("date_end", models.DateField(null=True, verbose_name="End date")),
+                (
+                    "comment",
+                    models.TextField(blank=True, null=True, verbose_name="Comment"),
+                ),
+                (
+                    "group",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="absences",
+                        to="core.Group",
+                        verbose_name="Group",
+                    ),
+                ),
+                (
+                    "period_from",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="Start period",
+                    ),
+                ),
+                (
+                    "period_to",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="chronos.TimePeriod",
+                        verbose_name="End period",
+                    ),
+                ),
+                (
+                    "reason",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="absences",
+                        to="chronos.AbsenceReason",
+                        verbose_name="Absence reason",
+                    ),
+                ),
+                (
+                    "room",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="absences",
+                        to="chronos.Room",
+                        verbose_name="Room",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="sites.Site",
+                    ),
+                ),
+                (
+                    "teacher",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="absences",
+                        to="core.Person",
+                        verbose_name="Teacher",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Absence',
-                'verbose_name_plural': 'Absences',
-                'ordering': ['date_start'],
+                "verbose_name": "Absence",
+                "verbose_name_plural": "Absences",
+                "ordering": ["date_start"],
             },
         ),
         migrations.AddIndex(
-            model_name='timeperiod',
-            index=models.Index(fields=['time_start', 'time_end'], name='chronos_tim_time_st_491e4c_idx'),
+            model_name="timeperiod",
+            index=models.Index(
+                fields=["time_start", "time_end"], name="chronos_tim_time_st_491e4c_idx"
+            ),
         ),
         migrations.AlterUniqueTogether(
-            name='timeperiod',
-            unique_together={('weekday', 'period')},
+            name="timeperiod", unique_together={("weekday", "period")},
         ),
         migrations.AddConstraint(
-            model_name='lessonsubstitution',
-            constraint=models.CheckConstraint(check=models.Q(('cancelled', True), ('subject__isnull', False), _negated=True), name='either_substituted_or_cancelled'),
+            model_name="lessonsubstitution",
+            constraint=models.CheckConstraint(
+                check=models.Q(
+                    ("cancelled", True), ("subject__isnull", False), _negated=True
+                ),
+                name="either_substituted_or_cancelled",
+            ),
         ),
         migrations.AlterUniqueTogether(
-            name='lessonsubstitution',
-            unique_together={('lesson_period', 'week')},
+            name="lessonsubstitution", unique_together={("lesson_period", "week")},
         ),
         migrations.AddIndex(
-            model_name='lessonperiod',
-            index=models.Index(fields=['lesson', 'period'], name='chronos_les_lesson__05250e_idx'),
+            model_name="lessonperiod",
+            index=models.Index(
+                fields=["lesson", "period"], name="chronos_les_lesson__05250e_idx"
+            ),
         ),
         migrations.AddIndex(
-            model_name='lesson',
-            index=models.Index(fields=['date_start', 'date_end'], name='chronos_les_date_st_5ecc62_idx'),
+            model_name="lesson",
+            index=models.Index(
+                fields=["date_start", "date_end"], name="chronos_les_date_st_5ecc62_idx"
+            ),
         ),
         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.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_period__c7ec33_idx'),
+            model_name="event",
+            index=models.Index(
+                fields=["period_from", "period_to", "date_start", "date_end"],
+                name="chronos_eve_period__c7ec33_idx",
+            ),
         ),
         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",
+            ),
         ),
         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"
+            ),
         ),
     ]
diff --git a/aleksis/apps/chronos/model_extensions.py b/aleksis/apps/chronos/model_extensions.py
index c98235fc05838aff737c2076dc29d0a68a9c51ad..3a288a299651296dd7c1e78a941f6982fe48d616 100644
--- a/aleksis/apps/chronos/model_extensions.py
+++ b/aleksis/apps/chronos/model_extensions.py
@@ -86,7 +86,9 @@ def for_timetables(cls):
 
 Announcement.class_method(for_timetables)
 Announcement.field(
-    show_in_timetables=BooleanField(verbose_name=_("Show announcement in timetable views?"))
+    show_in_timetables=BooleanField(
+        verbose_name=_("Show announcement in timetable views?")
+    )
 )
 
 Group.foreign_key("subject", Subject, related_name="groups")
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 025d83ddfc73b409d11418013b2ea814d6cadab6..c785aba056554a05c93173a35f754b9386b0206a 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -44,7 +44,9 @@ 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"))
@@ -75,12 +77,16 @@ class TimePeriod(ExtensibleModel):
 
         return wanted_week[self.weekday]
 
-    def get_datetime_start(self, week: Optional[Union[CalendarWeek, int]] = None) -> datetime:
+    def get_datetime_start(
+        self, week: Optional[Union[CalendarWeek, int]] = None
+    ) -> datetime:
         """Get datetime of lesson start in a specific week."""
         day = self.get_date(week)
         return datetime.combine(day, self.time_start)
 
-    def get_datetime_end(self, week: Optional[Union[CalendarWeek, int]] = None) -> datetime:
+    def get_datetime_end(
+        self, week: Optional[Union[CalendarWeek, int]] = None
+    ) -> datetime:
         """Get datetime of lesson end in a specific week."""
         day = self.get_date(week)
         return datetime.combine(day, self.time_end)
@@ -127,11 +133,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]:
@@ -143,11 +153,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"]]
@@ -158,7 +172,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)
@@ -174,7 +190,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:
@@ -188,15 +206,23 @@ class Room(ExtensibleModel):
 
 class Lesson(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
     subject = models.ForeignKey(
-        "Subject", on_delete=models.CASCADE, related_name="lessons", verbose_name=_("Subject"),
+        "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"),
+        "TimePeriod",
+        related_name="lessons",
+        through="LessonPeriod",
+        verbose_name=_("Periods"),
+    )
+    groups = models.ManyToManyField(
+        "core.Group", related_name="lessons", verbose_name=_("Groups")
     )
-    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)
@@ -221,7 +247,9 @@ 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")
@@ -236,9 +264,14 @@ 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(
@@ -249,7 +282,9 @@ class LessonSubstitution(ExtensibleModel):
 
     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):
@@ -283,14 +318,24 @@ class LessonPeriod(ExtensibleModel):
     objects = LessonPeriodManager.from_queryset(LessonPeriodQuerySet)()
 
     lesson = models.ForeignKey(
-        "Lesson", models.CASCADE, related_name="lesson_periods", verbose_name=_("Lesson"),
+        "Lesson",
+        models.CASCADE,
+        related_name="lesson_periods",
+        verbose_name=_("Lesson"),
     )
     period = models.ForeignKey(
-        "TimePeriod", models.CASCADE, related_name="lesson_periods", verbose_name=_("Time period"),
+        "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.CASCADE,
+        null=True,
+        related_name="lesson_periods",
+        verbose_name=_("Room"),
     )
 
     def get_substitution(self, week: Optional[int] = None) -> LessonSubstitution:
@@ -380,7 +425,9 @@ class TimetableWidget(DashboardWidget):
 
         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
@@ -414,7 +461,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:
@@ -501,7 +550,10 @@ class Absence(ExtensibleModel):
 
 class Exam(ExtensibleModel):
     lesson = models.ForeignKey(
-        "Lesson", on_delete=models.CASCADE, related_name="exams", verbose_name=_("Lesson"),
+        "Lesson",
+        on_delete=models.CASCADE,
+        related_name="exams",
+        verbose_name=_("Lesson"),
     )
 
     date = models.DateField(verbose_name=_("Date of exam"), null=True)
@@ -606,15 +658,27 @@ class Break(ExtensibleModel):
 
     @property
     def weekday(self):
-        return self.after_period.weekday if self.after_period else self.before_period.weekday
+        return (
+            self.after_period.weekday
+            if self.after_period
+            else self.before_period.weekday
+        )
 
     @property
     def after_period_number(self):
-        return self.after_period.period if self.after_period else self.before_period.period - 1
+        return (
+            self.after_period.period
+            if self.after_period
+            else self.before_period.period - 1
+        )
 
     @property
     def before_period_number(self):
-        return self.before_period.period if self.before_period else self.after_period.period + 1
+        return (
+            self.before_period.period
+            if self.before_period
+            else self.after_period.period + 1
+        )
 
     @property
     def time_start(self):
@@ -655,10 +719,15 @@ class Supervision(ExtensibleModel):
         Break, models.CASCADE, verbose_name=_("Break"), related_name="supervisions"
     )
     teacher = models.ForeignKey(
-        "core.Person", models.CASCADE, related_name="supervisions", verbose_name=_("Teacher"),
+        "core.Person",
+        models.CASCADE,
+        related_name="supervisions",
+        verbose_name=_("Teacher"),
     )
 
-    def get_substitution(self, week: Optional[int] = None) -> Optional[SupervisionSubstitution]:
+    def get_substitution(
+        self, week: Optional[int] = None
+    ) -> Optional[SupervisionSubstitution]:
         wanted_week = week or getattr(self, "_week", None) or CalendarWeek().week
         wanted_week = CalendarWeek(week=wanted_week)
         # We iterate over all substitutions because this can make use of
@@ -686,7 +755,10 @@ class Supervision(ExtensibleModel):
 class SupervisionSubstitution(ExtensibleModel):
     date = models.DateField(verbose_name=_("Date"))
     supervision = models.ForeignKey(
-        Supervision, models.CASCADE, verbose_name=_("Supervision"), related_name="substitutions",
+        Supervision,
+        models.CASCADE,
+        verbose_name=_("Supervision"),
+        related_name="substitutions",
     )
     teacher = models.ForeignKey(
         "core.Person",
@@ -713,7 +785,9 @@ class Event(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
 
     objects = CurrentSiteManager.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)
@@ -725,11 +799,18 @@ class Event(ExtensibleModel, GroupPropertiesMixin, TeacherPropertiesMixin):
         related_name="+",
     )
     period_to = models.ForeignKey(
-        "TimePeriod", on_delete=models.CASCADE, verbose_name=_("End time period"), related_name="+",
+        "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"))
+    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")
     )
@@ -758,7 +839,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")
 
@@ -768,9 +851,14 @@ class ExtraLesson(ExtensibleModel, GroupPropertiesMixin):
 
     objects = CurrentSiteManager.from_queryset(ExtraLessonQuerySet)()
 
-    week = models.IntegerField(verbose_name=_("Week"), default=CalendarWeek.current_week)
+    week = models.IntegerField(
+        verbose_name=_("Week"), default=CalendarWeek.current_week
+    )
     period = models.ForeignKey(
-        "TimePeriod", models.CASCADE, related_name="extra_lessons", verbose_name=_("Time period"),
+        "TimePeriod",
+        models.CASCADE,
+        related_name="extra_lessons",
+        verbose_name=_("Time period"),
     )
 
     subject = models.ForeignKey(
@@ -783,13 +871,21 @@ class ExtraLesson(ExtensibleModel, GroupPropertiesMixin):
         "core.Group", related_name="extra_lessons", verbose_name=_("Groups")
     )
     teachers = models.ManyToManyField(
-        "core.Person", related_name="extra_lessons_as_teacher", verbose_name=_("Teachers"),
+        "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"),
+        "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 f"{self.week}, {self.period}, {self.subject}"
diff --git a/aleksis/apps/chronos/preferences.py b/aleksis/apps/chronos/preferences.py
index cddfb3f0c8be0fbf9f2aeeafa27fcec971a318c0..4230ceaa88797ebaf32704b695dd2553b8a816e2 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 person_preferences_registry, site_preferences_registry
+from aleksis.core.registries import (
+    person_preferences_registry,
+    site_preferences_registry,
+)
 
 chronos = Section("chronos", verbose_name=_("Chronos"))
 
@@ -27,7 +30,9 @@ class ShortenGroups(BooleanPreference):
     name = "shorten_groups"
     default = True
     verbose_name = _("Shorten groups in timetable views")
-    help_text = _("If there are more groups than the set limit, they will be collapsed.")
+    help_text = _(
+        "If there are more groups than the set limit, they will be collapsed."
+    )
 
 
 @site_preferences_registry.register
diff --git a/aleksis/apps/chronos/rules.py b/aleksis/apps/chronos/rules.py
index 7ee9d1e0dcfb7b937b24ef82bb1adf36fa10dc46..d780725cb1f6a4e56be12d1db83280a79efd191a 100644
--- a/aleksis/apps/chronos/rules.py
+++ b/aleksis/apps/chronos/rules.py
@@ -11,7 +11,9 @@ from .models import LessonSubstitution
 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
diff --git a/aleksis/apps/chronos/tables.py b/aleksis/apps/chronos/tables.py
index bc4011f3ef0ebaaad9509ae0d55d9b7a245f675d..92a966fe11a3d866bdd9d160ebba712ab4e3066d 100644
--- a/aleksis/apps/chronos/tables.py
+++ b/aleksis/apps/chronos/tables.py
@@ -31,8 +31,12 @@ class LessonsTable(tables.Table):
         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(
diff --git a/aleksis/apps/chronos/templatetags/week_helpers.py b/aleksis/apps/chronos/templatetags/week_helpers.py
index c97703175ec5c4f39cf1757b5ee426bddb4e0dbb..727afdf7bf99d28363f84cdba08f21233974df18 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 666183ec6a43d80b897b05643288a77ee8b615b7..3d68c3a18451570254e2d5323221bd12a31352ba 100644
--- a/aleksis/apps/chronos/urls.py
+++ b/aleksis/apps/chronos/urls.py
@@ -17,11 +17,15 @@ urlpatterns = [
         name="timetable_by_week",
     ),
     path(
-        "timetable/<str:type_>/<int:pk>/<str:regular>/", views.timetable, name="timetable_regular",
+        "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",
+        "lessons/<int:year>/<int:month>/<int:day>/",
+        views.lessons_day,
+        name="lessons_day_by_date",
     ),
     path(
         "lessons/<int:id_>/<int:week>/substition/",
@@ -35,7 +39,10 @@ urlpatterns = [
     ),
     path("substitutions/", views.substitutions, name="substitutions"),
     path(
-        "substitutions/print/", views.substitutions, {"is_print": True}, name="substitutions_print",
+        "substitutions/print/",
+        views.substitutions,
+        {"is_print": True},
+        name="substitutions_print",
     ),
     path(
         "substitutions/<int:year>/<int:month>/<int:day>/",
diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py
index a5290ebbbf2a18013acb98cf17b6be57752847cd..fa0a3f85aa4404ec7ca9d20939658e42a475af6a 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 = []
 
@@ -48,7 +50,9 @@ def build_timetable(
     if is_person:
         lesson_periods = LessonPeriod.objects.daily_lessons_for_person(obj, date_ref)
     else:
-        lesson_periods = LessonPeriod.objects.in_week(date_ref).filter_from_type(type_, obj)
+        lesson_periods = LessonPeriod.objects.in_week(date_ref).filter_from_type(
+            type_, obj
+        )
 
     # Sort lesson periods in a dict
     lesson_periods_per_period = lesson_periods.group_by_periods(is_person=is_person)
@@ -57,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)
@@ -124,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())
@@ -138,7 +146,10 @@ def build_timetable(
             if period_after_break not in needed_breaks:
                 needed_breaks.append(period_after_break)
 
-            if not is_person and period_after_break not in supervisions_per_period_after:
+            if (
+                not is_person
+                and period_after_break not in supervisions_per_period_after
+            ):
                 supervisions_per_period_after[period_after_break] = {}
 
             if is_person:
@@ -164,7 +175,9 @@ def build_timetable(
             if not is_person:
                 cols = []
 
-                for weekday in range(TimePeriod.weekday_min, TimePeriod.weekday_max + 1):
+                for weekday in range(
+                    TimePeriod.weekday_min, TimePeriod.weekday_max + 1
+                ):
                     col = None
                     if (
                         period in supervisions_per_period_after
@@ -193,21 +206,32 @@ def build_timetable(
 
             if not is_person:
                 cols = []
-                for weekday in range(TimePeriod.weekday_min, TimePeriod.weekday_max + 1):
+                for weekday in range(
+                    TimePeriod.weekday_min, TimePeriod.weekday_max + 1
+                ):
                     col = []
 
                     # Add lesson periods
-                    if period in lesson_periods_per_period and weekday not in holidays_per_weekday:
+                    if (
+                        period in lesson_periods_per_period
+                        and weekday not in holidays_per_weekday
+                    ):
                         if weekday in lesson_periods_per_period[period]:
                             col += lesson_periods_per_period[period][weekday]
 
                     # Add extra lessons
-                    if period in extra_lessons_per_period and weekday not in holidays_per_weekday:
+                    if (
+                        period in extra_lessons_per_period
+                        and weekday not in holidays_per_weekday
+                    ):
                         if weekday in extra_lessons_per_period[period]:
                             col += extra_lessons_per_period[period][weekday]
 
                     # Add events
-                    if period in events_per_period and weekday not in holidays_per_weekday:
+                    if (
+                        period in events_per_period
+                        and weekday not in holidays_per_weekday
+                    ):
                         if weekday in events_per_period[period]:
                             col += events_per_period[period][weekday]
 
@@ -304,7 +328,9 @@ def build_substitutions_list(wanted_day: date) -> List[dict]:
     return rows
 
 
-def build_weekdays(base: List[Tuple[int, str]], wanted_week: CalendarWeek) -> List[dict]:
+def build_weekdays(
+    base: List[Tuple[int, str]], wanted_week: CalendarWeek
+) -> List[dict]:
     holidays_per_weekday = Holiday.in_week(wanted_week)
 
     weekdays = []
@@ -314,7 +340,9 @@ def build_weekdays(base: List[Tuple[int, str]], wanted_week: CalendarWeek) -> Li
             "key": key,
             "name": name,
             "date": wanted_week[key],
-            "holiday": holidays_per_weekday[key] if key in holidays_per_weekday else None,
+            "holiday": holidays_per_weekday[key]
+            if key in holidays_per_weekday
+            else None,
         }
         weekdays.append(weekday)
 
diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py
index 96a332d946053fcb6364c717e3c4e4cea07bac7e..398db0e6505228b0d2432307d45fd885cb05fd2c 100644
--- a/aleksis/apps/chronos/views.py
+++ b/aleksis/apps/chronos/views.py
@@ -30,16 +30,19 @@ def all_timetables(request: HttpRequest) -> HttpResponse:
     """View all timetables for persons, groups and rooms."""
     context = {}
 
-    teachers = Person.objects.annotate(lessons_count=Count("lessons_as_teacher")).filter(
-        lessons_count__gt=0
-    )
+    teachers = Person.objects.annotate(
+        lessons_count=Count("lessons_as_teacher")
+    ).filter(lessons_count__gt=0)
     groups = Group.objects.annotate(
-        lessons_count=Count("lessons"), child_lessons_count=Count("child_groups__lessons"),
+        lessons_count=Count("lessons"),
+        child_lessons_count=Count("child_groups__lessons"),
     )
     classes = groups.filter(lessons_count__gt=0, parent_groups=None) | groups.filter(
         child_lessons_count__gt=0, parent_groups=None
     )
-    rooms = Room.objects.annotate(lessons_count=Count("lesson_periods")).filter(lessons_count__gt=0)
+    rooms = Room.objects.annotate(lessons_count=Count("lesson_periods")).filter(
+        lessons_count__gt=0
+    )
 
     context["teachers"] = teachers
     context["classes"] = classes
@@ -62,7 +65,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
@@ -133,7 +138,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
@@ -180,7 +187,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)
@@ -234,7 +243,9 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
             messages.success(request, _("The substitution has been saved."))
 
             date = wanted_week[lesson_period.period.weekday]
-            return redirect("lessons_day_by_date", year=date.year, month=date.month, day=date.day)
+            return redirect(
+                "lessons_day_by_date", year=date.year, month=date.month, day=date.day
+            )
 
     context["edit_substitution_form"] = edit_substitution_form
 
@@ -255,7 +266,9 @@ def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpRespon
     messages.success(request, _("The substitution has been deleted."))
 
     date = wanted_week[lesson_period.period.weekday]
-    return redirect("lessons_day_by_date", year=date.year, month=date.month, day=date.day)
+    return redirect(
+        "lessons_day_by_date", year=date.year, month=date.month, day=date.day
+    )
 
 
 @permission_required("chronos.view_substitutions")
@@ -273,7 +286,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 = {}