diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index 326390ac1524fffca477a4e94f68216d851c0a1c..2b2b6c4c4200b2f432f611fa7181ff4bc5d5bb1f 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta
 from enum import Enum
 from typing import Optional, Union
 
-from django.contrib.sites.managers import CurrentSiteManager
+from django.contrib.sites.managers import CurrentSiteManager as _CurrentSiteManager
 from django.db import models
 from django.db.models import Count, F, Q
 
@@ -13,6 +13,10 @@ from aleksis.core.models import Group, Person
 from aleksis.core.util.core_helpers import get_site_preferences
 
 
+class CurrentSiteManager(_CurrentSiteManager):
+    use_in_migrations = False
+
+
 class TimetableType(Enum):
     """Enum for different types of timetables."""
 
diff --git a/aleksis/apps/chronos/migrations/0001_initial.py b/aleksis/apps/chronos/migrations/0001_initial.py
index a5273c7889a7d9d4fa9eaeadb0e144f9e9ff1a28..892b7a0303250fb221e58d8906a49ab14fa0afe8 100644
--- a/aleksis/apps/chronos/migrations/0001_initial.py
+++ b/aleksis/apps/chronos/migrations/0001_initial.py
@@ -1,11 +1,12 @@
-# Generated by Django 2.2.5 on 2019-09-03 18:30
+# Generated by Django 3.0.5 on 2020-05-04 12:00
 
-import django.core.validators
-import django.db.models.deletion
+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 aleksis.apps.chronos.util.date
-import aleksis.core.util.core_helpers
+import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -13,335 +14,449 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ("core", "0001_initial"),
+        ('core', '0001_initial'),
+        ('sites', '0002_alter_domain_unique'),
     ]
 
     operations = [
         migrations.CreateModel(
-            name="Lesson",
+            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)),
+            ],
+            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,
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            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')),
+            ],
+            options={
+                'verbose_name': 'Break',
+                'verbose_name_plural': 'Breaks',
+                'ordering': ['after_period'],
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            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')),
+            ],
+            options={
+                '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()),
+            ],
+        ),
+        migrations.CreateModel(
+            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')),
+            ],
+            options={
+                'verbose_name': 'Lesson period',
+                'verbose_name_plural': 'Lesson periods',
+                'ordering': ['lesson__date_start', 'period__weekday', 'period__period', 'lesson__subject'],
+            },
+        ),
+        migrations.CreateModel(
+            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)),
+            ],
+            options={
+                'verbose_name': 'Supervision',
+                'verbose_name_plural': 'Supervisions',
+                'ordering': ['area', 'break_item'],
+            },
+        ),
+        migrations.CreateModel(
+            name='TimetableWidget',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'Timetable widget',
+                'verbose_name_plural': 'Timetable widgets',
+                'proxy': True,
+                'indexes': [],
+                'constraints': [],
+            },
+            bases=('core.dashboardwidget',),
+        ),
+        migrations.CreateModel(
+            name='TimePeriod',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "date_start",
-                    models.DateField(
-                        null=True, verbose_name="Effective start date of lesson"
-                    ),
-                ),
-                (
-                    "date_end",
-                    models.DateField(
-                        null=True, verbose_name="Effective end date of lesson"
-                    ),
-                ),
-                (
-                    "groups",
-                    models.ManyToManyField(related_name="lessons", to="core.Group"),
-                ),
+                ('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, 'Montag'), (1, 'Dienstag'), (2, 'Mittwoch'), (3, 'Donnerstag'), (4, 'Freitag'), (5, 'Samstag'), (6, 'Sonntag')], 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'],
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
             ],
-            options={"ordering": ["date_start"],},
         ),
         migrations.CreateModel(
-            name="LessonPeriod",
+            name='SupervisionSubstitution',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "lesson",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="lesson_periods",
-                        to="chronos.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)),
+                ('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={
-                "ordering": ["lesson__date_start", "period__weekday", "period__period"],
+                'verbose_name': 'Supervision substitution',
+                'verbose_name_plural': 'Supervision substitutions',
+                'ordering': ['date', 'supervision'],
             },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
         ),
         migrations.CreateModel(
-            name="TimePeriod",
+            name='SupervisionArea',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "weekday",
-                    models.PositiveSmallIntegerField(
-                        choices=[
-                            (0, "Sunday"),
-                            (1, "Monday"),
-                            (2, "Tuesday"),
-                            (3, "Wednesday"),
-                            (4, "Thursday"),
-                            (5, "Friday"),
-                            (6, "Saturday"),
-                        ],
-                        verbose_name="Week day",
-                    ),
-                ),
-                (
-                    "period",
-                    models.PositiveSmallIntegerField(verbose_name="Number of period"),
-                ),
-                ("time_start", models.TimeField(verbose_name="Time the period starts")),
-                ("time_end", models.TimeField(verbose_name="Time the period ends")),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
+                ('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={
-                "ordering": ["weekday", "period"],
-                "unique_together": {("school", "weekday", "period")},
+                'verbose_name': 'Supervision area',
+                'verbose_name_plural': 'Supervision areas',
+                'ordering': ['name'],
             },
+            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'),
+        ),
+        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'),
+        ),
+        migrations.AddField(
+            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'),
         ),
         migrations.CreateModel(
-            name="Subject",
+            name='Subject',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "abbrev",
-                    models.CharField(
-                        max_length=10,
-                        verbose_name="Abbreviation of subject in timetable",
-                    ),
-                ),
-                (
-                    "name",
-                    models.CharField(
-                        max_length=30, verbose_name="Long name of subject"
-                    ),
-                ),
-                (
-                    "colour_fg",
-                    models.CharField(
-                        blank=True,
-                        max_length=7,
-                        validators=[
-                            django.core.validators.RegexValidator("#[0-9A-F]{6}")
-                        ],
-                        verbose_name="Foreground colour in timetable",
-                    ),
-                ),
-                (
-                    "colour_bg",
-                    models.CharField(
-                        blank=True,
-                        max_length=7,
-                        validators=[
-                            django.core.validators.RegexValidator("#[0-9A-F]{6}")
-                        ],
-                        verbose_name="Background colour in timetable",
-                    ),
-                ),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
+                ('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='#FFFFFF', max_length=18, verbose_name='Foreground colour')),
+                ('colour_bg', colorfield.fields.ColorField(blank=True, default='#FFFFFF', 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={
-                "ordering": ["name", "abbrev"],
-                "unique_together": {("school", "abbrev"), ("school", "name")},
+                'verbose_name': 'Subject',
+                'verbose_name_plural': 'Subjects',
+                'ordering': ['name', 'short_name'],
             },
+            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",
-                    ),
-                ),
-                (
-                    "short_name",
-                    models.CharField(
-                        max_length=10, verbose_name="Short name, e.g. room number"
-                    ),
-                ),
-                ("name", models.CharField(max_length=30, verbose_name="Long name")),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
+                ('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={
-                "ordering": ["name", "short_name"],
-                "unique_together": {("school", "name"), ("school", "short_name")},
+                'verbose_name': 'Room',
+                'verbose_name_plural': 'Rooms',
+                'ordering': ['name', 'short_name'],
             },
+            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",
-                    ),
-                ),
-                (
-                    "week",
-                    models.IntegerField(
-                        default=aleksis.apps.chronos.util.date.CalendarWeek.current_week,
-                        verbose_name="Week",
-                    ),
-                ),
-                (
-                    "lesson_period",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="substitutions",
-                        to="chronos.LessonPeriod",
-                    ),
-                ),
-                (
-                    "room",
-                    models.ForeignKey(
-                        null=True,
-                        blank=True,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="chronos.Room",
-                        verbose_name="Room",
-                    ),
-                ),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
-                (
-                    "subject",
-                    models.ForeignKey(
-                        null=True,
-                        blank=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",
-                    ),
-                ),
+                ('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, 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={
-                "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",
-            ),
+            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'),
+        ),
+        migrations.AddField(
+            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'),
         ),
         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",
-            ),
+            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="lessonperiod",
-            name="school",
-            field=models.ForeignKey(
-                default=1, on_delete=django.db.models.deletion.CASCADE, to="core.School"
-            ),
+            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="periods",
-            field=models.ManyToManyField(
-                related_name="lessons",
-                through="chronos.LessonPeriod",
-                to="chronos.TimePeriod",
-            ),
+            model_name='lesson',
+            name='teachers',
+            field=models.ManyToManyField(related_name='lessons_as_teacher', to='core.Person', verbose_name='Teachers'),
+        ),
+        migrations.CreateModel(
+            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, 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'],
+            },
+        ),
+        migrations.CreateModel(
+            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, 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',
+            },
+            bases=(models.Model, aleksis.apps.chronos.managers.GroupPropertiesMixin),
+        ),
+        migrations.CreateModel(
+            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, 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'],
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            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, 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'],
+            },
+            bases=(models.Model, aleksis.apps.chronos.managers.GroupPropertiesMixin, aleksis.apps.chronos.managers.TeacherPropertiesMixin),
         ),
         migrations.AddField(
-            model_name="lesson",
-            name="school",
-            field=models.ForeignKey(
-                default=1, on_delete=django.db.models.deletion.CASCADE, to="core.School"
-            ),
+            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="lesson",
-            name="subject",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="lessons",
-                to="chronos.Subject",
-            ),
+            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="lesson",
-            name="teachers",
-            field=models.ManyToManyField(related_name="lessons", to="core.Person"),
+            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',
+            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, 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',
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            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, 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'],
+            },
+        ),
+        migrations.AddIndex(
+            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')},
+        ),
+        migrations.AddConstraint(
+            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')},
+        ),
+        migrations.AddIndex(
+            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'),
+        ),
+        migrations.AddIndex(
+            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'),
+        ),
+        migrations.AddIndex(
+            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'),
+        ),
+        migrations.AddIndex(
+            model_name='absence',
+            index=models.Index(fields=['date_start', 'date_end'], name='chronos_abs_date_st_337ff5_idx'),
         ),
     ]
diff --git a/aleksis/apps/chronos/migrations/0002_db_indexes.py b/aleksis/apps/chronos/migrations/0002_db_indexes.py
deleted file mode 100644
index f6ee2fe1cf4fd021c8c1c00b75f6d349b3f3978c..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0002_db_indexes.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Generated by Django 2.2.4 on 2019-09-04 13:22
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("core", "0001_initial"),
-        ("chronos", "0001_initial"),
-    ]
-
-    operations = [
-        migrations.AlterUniqueTogether(
-            name="lessonsubstitution",
-            unique_together={("school", "lesson_period", "week")},
-        ),
-        migrations.AddIndex(
-            model_name="lesson",
-            index=models.Index(
-                fields=["date_start", "date_end"], name="chronos_les_date_st_5ecc62_idx"
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="lessonperiod",
-            index=models.Index(
-                fields=["lesson", "period"], name="chronos_les_lesson__05250e_idx"
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="timeperiod",
-            index=models.Index(
-                fields=["time_start", "time_end"], name="chronos_tim_time_st_491e4c_idx"
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0003_substitution_cancelled_or_subject.py b/aleksis/apps/chronos/migrations/0003_substitution_cancelled_or_subject.py
deleted file mode 100644
index a7486e4702fadab910c7e59e230ffbffca20ea30..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0003_substitution_cancelled_or_subject.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated by Django 2.2.5 on 2019-09-07 14:19
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0002_db_indexes"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="lessonsubstitution",
-            name="cancelled",
-            field=models.BooleanField(default=False),
-        ),
-        migrations.AddConstraint(
-            model_name="lessonsubstitution",
-            constraint=models.CheckConstraint(
-                check=models.Q(
-                    ("cancelled", True), ("subject__isnull", False), _negated=True
-                ),
-                name="either_substituted_or_cancelled",
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0004_room_name_not_unique.py b/aleksis/apps/chronos/migrations/0004_room_name_not_unique.py
deleted file mode 100644
index c862d32086b74b71c9a1715f53993a82623e3e48..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0004_room_name_not_unique.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Generated by Django 2.2.5 on 2019-09-14 16:17
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0003_substitution_cancelled_or_subject"),
-    ]
-
-    operations = [
-        migrations.AlterUniqueTogether(
-            name="room", unique_together={("school", "short_name")},
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0005_remove_school_related.py b/aleksis/apps/chronos/migrations/0005_remove_school_related.py
deleted file mode 100644
index 7d3ba123a3c1f91565b61957f29594e705007b1c..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0005_remove_school_related.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Generated by Django 3.0.2 on 2020-01-10 16:37
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("core", "0008_rename_fields_notification_activity"),
-        ("chronos", "0004_room_name_not_unique"),
-    ]
-
-    operations = [
-        migrations.RemoveField(model_name="lesson", name="school",),
-        migrations.RemoveField(model_name="lessonperiod", name="school",),
-        migrations.AlterField(
-            model_name="lesson",
-            name="teachers",
-            field=models.ManyToManyField(
-                related_name="lessons_as_teacher", to="core.Person"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="room",
-            name="short_name",
-            field=models.CharField(
-                max_length=10, unique=True, verbose_name="Short name, e.g. room number"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="subject",
-            name="abbrev",
-            field=models.CharField(
-                max_length=10,
-                unique=True,
-                verbose_name="Abbreviation of subject in timetable",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="subject",
-            name="name",
-            field=models.CharField(
-                max_length=30, unique=True, verbose_name="Long name of subject"
-            ),
-        ),
-        migrations.AlterUniqueTogether(
-            name="lessonsubstitution", unique_together={("lesson_period", "week")},
-        ),
-        migrations.AlterUniqueTogether(name="room", unique_together=set(),),
-        migrations.AlterUniqueTogether(name="subject", unique_together=set(),),
-        migrations.AlterUniqueTogether(
-            name="timeperiod", unique_together={("weekday", "period")},
-        ),
-        migrations.RemoveField(model_name="lessonsubstitution", name="school",),
-        migrations.RemoveField(model_name="room", name="school",),
-        migrations.RemoveField(model_name="subject", name="school",),
-        migrations.RemoveField(model_name="timeperiod", name="school",),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0006_extended_data.py b/aleksis/apps/chronos/migrations/0006_extended_data.py
deleted file mode 100644
index 6cbea6402c3a9d5d0dedf97cb40fc11ebe9e5115..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0006_extended_data.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated by Django 3.0.2 on 2020-01-19 13:15
-
-import django.contrib.postgres.fields.jsonb
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0005_remove_school_related"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="lessonperiod",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py b/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py
deleted file mode 100644
index 9079ed95da7d99e78ccd1ce49421bc12ae44f0b7..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0007_advanced_models_from_untis.py
+++ /dev/null
@@ -1,554 +0,0 @@
-# Generated by Django 3.0.3 on 2020-03-08 20:16
-
-import django.contrib.postgres.fields.jsonb
-import django.db.models.deletion
-from django.db import migrations, models
-
-import colorfield.fields
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0006_extended_data"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="Absence",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                (
-                    "date_start",
-                    models.DateField(
-                        null=True, verbose_name="Effective start date of absence"
-                    ),
-                ),
-                (
-                    "date_end",
-                    models.DateField(
-                        null=True, verbose_name="Effective end date of absence"
-                    ),
-                ),
-                (
-                    "comment",
-                    models.TextField(verbose_name="Comment", null=True, blank=True),
-                ),
-            ],
-            options={
-                "verbose_name": "Absence",
-                "verbose_name_plural": "Absences",
-                "ordering": ["date_start"],
-            },
-        ),
-        migrations.CreateModel(
-            name="AbsenceReason",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                ("title", models.CharField(max_length=50, verbose_name="Title")),
-                (
-                    "description",
-                    models.TextField(verbose_name="Description", null=True, blank=True),
-                ),
-            ],
-            options={
-                "verbose_name": "Absence reason",
-                "verbose_name_plural": "Absence reasons",
-            },
-        ),
-        migrations.CreateModel(
-            name="Event",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                ("title", models.CharField(max_length=50, verbose_name="Title")),
-                (
-                    "date_start",
-                    models.DateField(
-                        null=True, verbose_name="Effective start date of event"
-                    ),
-                ),
-                (
-                    "date_end",
-                    models.DateField(
-                        null=True, verbose_name="Effective end date of event"
-                    ),
-                ),
-            ],
-            options={
-                "verbose_name": "Events",
-                "verbose_name_plural": "Events",
-                "ordering": ["date_start"],
-            },
-        ),
-        migrations.CreateModel(
-            name="Exam",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                ("date", models.DateField(null=True, verbose_name="Date of exam")),
-                ("title", models.CharField(max_length=50, verbose_name="Title")),
-                (
-                    "comment",
-                    models.TextField(verbose_name="Comment", null=True, blank=True),
-                ),
-            ],
-            options={
-                "verbose_name": "Exam",
-                "verbose_name_plural": "Exams",
-                "ordering": ["date"],
-            },
-        ),
-        migrations.CreateModel(
-            name="Holiday",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                (
-                    "title",
-                    models.CharField(
-                        max_length=50, verbose_name="Title of the holidays"
-                    ),
-                ),
-                (
-                    "date_start",
-                    models.DateField(
-                        null=True, verbose_name="Effective start date of holidays"
-                    ),
-                ),
-                (
-                    "date_end",
-                    models.DateField(
-                        null=True, verbose_name="Effective end date of holidays"
-                    ),
-                ),
-                (
-                    "comments",
-                    models.TextField(verbose_name="Comments", null=True, blank=True),
-                ),
-            ],
-            options={
-                "verbose_name": "Holiday",
-                "verbose_name_plural": "Holidays",
-                "ordering": ["date_start"],
-            },
-        ),
-        migrations.CreateModel(
-            name="SupervisionArea",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                (
-                    "short_name",
-                    models.CharField(max_length=10, verbose_name="Short name"),
-                ),
-                ("name", models.CharField(max_length=50, verbose_name="Long name")),
-                (
-                    "colour_fg",
-                    colorfield.fields.ColorField(default="#000000", max_length=18),
-                ),
-                (
-                    "colour_bg",
-                    colorfield.fields.ColorField(default="#FFFFFF", max_length=18),
-                ),
-            ],
-            options={
-                "verbose_name": "Supervision areas",
-                "verbose_name_plural": "Supervision areas",
-                "ordering": ["name"],
-            },
-        ),
-        migrations.CreateModel(
-            name="Break",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-                (
-                    "short_name",
-                    models.CharField(max_length=10, verbose_name="Short name"),
-                ),
-                ("name", models.CharField(max_length=50, verbose_name="Long name")),
-                (
-                    "weekday",
-                    models.PositiveSmallIntegerField(
-                        choices=[
-                            (0, "Montag"),
-                            (1, "Dienstag"),
-                            (2, "Mittwoch"),
-                            (3, "Donnerstag"),
-                            (4, "Freitag"),
-                            (5, "Samstag"),
-                            (6, "Sonntag"),
-                        ],
-                        verbose_name="Week day",
-                    ),
-                ),
-                ("time_start", models.TimeField(verbose_name="Start time")),
-                ("time_end", models.TimeField(verbose_name="End time")),
-            ],
-            options={
-                "verbose_name": "Break",
-                "verbose_name_plural": "Breaks",
-                "ordering": ["weekday", "time_start"],
-            },
-        ),
-        migrations.CreateModel(
-            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
-                    ),
-                ),
-            ],
-            options={
-                "verbose_name": "Supervision",
-                "verbose_name_plural": "Supervisions",
-                "ordering": ["area", "break_item"],
-            },
-        ),
-        migrations.CreateModel(
-            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")),
-            ],
-            options={
-                "verbose_name": "Supervision substitution",
-                "verbose_name_plural": "Supervision substitutions",
-                "ordering": ["date", "supervision"],
-            },
-        ),
-        migrations.AddIndex(
-            model_name="holiday",
-            index=models.Index(
-                fields=["date_start", "date_end"], name="chronos_hol_date_st_a47004_idx"
-            ),
-        ),
-        migrations.AddField(
-            model_name="exam",
-            name="lesson",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="exams",
-                to="chronos.Lesson",
-            ),
-        ),
-        migrations.AddField(
-            model_name="exam",
-            name="period_from",
-            field=models.ForeignKey(
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective start period of exam",
-            ),
-        ),
-        migrations.AddField(
-            model_name="exam",
-            name="period_to",
-            field=models.ForeignKey(
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective end period of exam",
-            ),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="absence_reason",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="absence_reason",
-                to="chronos.AbsenceReason",
-                verbose_name="Absence reason",
-            ),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="teachers",
-            field=models.ManyToManyField(
-                related_name="events", to="core.Person", verbose_name="Teachers"
-            ),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="period_from",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective start period of event",
-            ),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="period_to",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective end period of event",
-            ),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="rooms",
-            field=models.ManyToManyField(
-                related_name="events", to="chronos.Room", verbose_name="Rooms"
-            ),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="period_from",
-            field=models.ForeignKey(
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective start period of absence",
-            ),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="period_to",
-            field=models.ForeignKey(
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="+",
-                to="chronos.TimePeriod",
-                verbose_name="Effective end period of absence",
-            ),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="person",
-            field=models.ManyToManyField(related_name="absences", to="core.Person"),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="reason",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="absences",
-                to="chronos.AbsenceReason",
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="exam",
-            index=models.Index(fields=["date"], name="chronos_exa_date_5ba442_idx"),
-        ),
-        migrations.AddIndex(
-            model_name="event",
-            index=models.Index(
-                fields=["period_from", "period_to", "date_start", "date_end"],
-                name="chronos_eve_periodf_56eb18_idx",
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="absence",
-            index=models.Index(
-                fields=["date_start", "date_end"], name="chronos_abs_date_st_337ff5_idx"
-            ),
-        ),
-        migrations.AddField(
-            model_name="lessonsubstitution",
-            name="cancelled_for_teachers",
-            field=models.BooleanField(
-                default=False, verbose_name="Cancelled for teachers?"
-            ),
-        ),
-        migrations.AddField(
-            model_name="lessonsubstitution",
-            name="comment",
-            field=models.TextField(blank=True, null=True, verbose_name="Comment"),
-        ),
-        migrations.AlterField(
-            model_name="lessonsubstitution",
-            name="cancelled",
-            field=models.BooleanField(default=False, verbose_name="Cancelled?"),
-        ),
-        migrations.AddField(
-            model_name="event",
-            name="groups",
-            field=models.ManyToManyField(
-                related_name="events", to="core.Group", verbose_name="Groups"
-            ),
-        ),
-        migrations.AddField(
-            model_name="supervisionsubstitution",
-            name="supervision",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="substitutions",
-                to="chronos.Supervision",
-                verbose_name="Supervision",
-            ),
-        ),
-        migrations.AddField(
-            model_name="supervisionsubstitution",
-            name="teacher",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="substituted_supervisions",
-                to="core.Person",
-                verbose_name="Teacher",
-            ),
-        ),
-        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",
-            ),
-        ),
-        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",
-            ),
-        ),
-        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",
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="break",
-            index=models.Index(
-                fields=["weekday", "time_start", "time_end"],
-                name="chronos_bre_weekday_165338_idx",
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0008_break_period.py b/aleksis/apps/chronos/migrations/0008_break_period.py
deleted file mode 100644
index dd8945d199e69acade0965af58402e9cd0da75a8..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0008_break_period.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Generated by Django 3.0.4 on 2020-03-28 20:24
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0007_advanced_models_from_untis"),
-    ]
-
-    operations = [
-        migrations.RemoveIndex(
-            model_name="break", name="chronos_bre_weekday_165338_idx",
-        ),
-        migrations.RemoveField(model_name="break", name="time_end",),
-        migrations.RemoveField(model_name="break", name="time_start",),
-        migrations.RemoveField(model_name="break", name="weekday",),
-        migrations.AddField(
-            model_name="break",
-            name="after_period",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="break_after",
-                to="chronos.TimePeriod",
-                verbose_name="Effective start of break",
-            ),
-        ),
-        migrations.AddField(
-            model_name="break",
-            name="before_period",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="break_before",
-                to="chronos.TimePeriod",
-                verbose_name="Effective end of break",
-            ),
-        ),
-        migrations.AddIndex(
-            model_name="break",
-            index=models.Index(
-                fields=["after_period", "before_period"],
-                name="chronos_bre_after_p_0f28d3_idx",
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0009_extended_data.py b/aleksis/apps/chronos/migrations/0009_extended_data.py
deleted file mode 100644
index ed65071f8878776a9e767ab09a9c49e069c4a06a..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0009_extended_data.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Generated by Django 3.0.4 on 2020-03-30 13:04
-
-import django.contrib.postgres.fields.jsonb
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0008_break_period"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="lesson",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-        migrations.AddField(
-            model_name="lessonsubstitution",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-        migrations.AddField(
-            model_name="room",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-        migrations.AddField(
-            model_name="subject",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-        migrations.AddField(
-            model_name="timeperiod",
-            name="extended_data",
-            field=django.contrib.postgres.fields.jsonb.JSONField(
-                default=dict, editable=False
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0010_absence_reason_name.py b/aleksis/apps/chronos/migrations/0010_absence_reason_name.py
deleted file mode 100644
index 95f05e8b63035b6b8b1f9b5b8fcba620647efb01..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0010_absence_reason_name.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-13 13:36
-
-from django.db import migrations, models
-from django.db.models import F
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0009_extended_data"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="absencereason",
-            name="name",
-            field=models.CharField(
-                default=F("description"),
-                blank=True,
-                max_length=255,
-                null=True,
-                verbose_name="Name",
-            ),
-        ),
-        migrations.AddField(
-            model_name="absencereason",
-            name="short_name",
-            field=models.CharField(
-                default=F("title"), max_length=255, verbose_name="Short name"
-            ),
-            preserve_default=False,
-        ),
-        migrations.RemoveField(model_name="absencereason", name="description",),
-        migrations.RemoveField(model_name="absencereason", name="title",),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py b/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py
deleted file mode 100644
index a4f9d800a596ab4941a05c8cf3876e46d10e9ed3..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0011_absence_for_groups_and_rooms.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-13 15:07
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0010_absence_reason_name"),
-    ]
-
-    operations = [
-        migrations.RemoveField(model_name="absence", name="person",),
-        migrations.AddField(
-            model_name="absence",
-            name="group",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="absences",
-                to="core.Group",
-            ),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="room",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="absences",
-                to="chronos.Room",
-            ),
-        ),
-        migrations.AddField(
-            model_name="absence",
-            name="teacher",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="absences",
-                to="core.Person",
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py b/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py
deleted file mode 100644
index 5bdaaee5e09b316ff0531c041a7ee79d392fe432..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0012_event_remove_absence_reason.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-13 16:07
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0011_absence_for_groups_and_rooms"),
-    ]
-
-    operations = [
-        migrations.RemoveField(model_name="event", name="absence_reason",),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0013_event_title_optional.py b/aleksis/apps/chronos/migrations/0013_event_title_optional.py
deleted file mode 100644
index 6f18311e5450a155dcab6c38a4efffeab878c3e1..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0013_event_title_optional.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-14 16:11
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0012_event_remove_absence_reason"),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name="event",
-            name="title",
-            field=models.CharField(
-                blank=True, max_length=255, null=True, verbose_name="Title"
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0014_extra_lesson.py b/aleksis/apps/chronos/migrations/0014_extra_lesson.py
deleted file mode 100644
index f93bde3995a221f191fe7f416c01110db47da179..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0014_extra_lesson.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-18 20:21
-
-import django.contrib.postgres.fields.jsonb
-import django.db.models.deletion
-from django.db import migrations, models
-
-import calendarweek.calendarweek
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0013_event_title_optional"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            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"
-                    ),
-                ),
-            ],
-            options={"abstract": False,},
-        ),
-        migrations.AddField(
-            model_name="extralesson",
-            name="groups",
-            field=models.ManyToManyField(
-                related_name="extra_lessons", to="core.Group", verbose_name="Groups"
-            ),
-        ),
-        migrations.AddField(
-            model_name="extralesson",
-            name="period",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="extra_lessons",
-                to="chronos.TimePeriod",
-            ),
-        ),
-        migrations.AddField(
-            model_name="extralesson",
-            name="room",
-            field=models.ForeignKey(
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="extra_lessons",
-                to="chronos.Room",
-                verbose_name="Room",
-            ),
-        ),
-        migrations.AddField(
-            model_name="extralesson",
-            name="subject",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="extra_lessons",
-                to="chronos.Subject",
-                verbose_name="Subject",
-            ),
-        ),
-        migrations.AddField(
-            model_name="extralesson",
-            name="teachers",
-            field=models.ManyToManyField(
-                related_name="extra_lessons_as_teacher",
-                to="core.Person",
-                verbose_name="Teachers",
-            ),
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py b/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py
deleted file mode 100644
index 4912dd0d5118f7938d2f2fb8346cd2f2d079bf38..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0015_rename_abbrev_to_short_name.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-27 13:52
-
-from django.db import migrations, models
-from django.db.models import F
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0014_extra_lesson"),
-    ]
-
-    operations = [
-        migrations.RenameField(
-            model_name="subject", old_name="abbrev", new_name="short_name",
-        ),
-        migrations.AlterModelOptions(
-            name="subject", options={"ordering": ["name", "short_name"]},
-        ),
-    ]
diff --git a/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py b/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py
deleted file mode 100644
index b43b2bf1061cb9f45143c87c67c07c0ee8fc907c..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/migrations/0016_add_globalpermissions.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Generated by Django 3.0.5 on 2020-04-30 19:03
-
-import django.contrib.postgres.fields.jsonb
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("chronos", "0015_rename_abbrev_to_short_name"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="GlobalPermissions",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "extended_data",
-                    django.contrib.postgres.fields.jsonb.JSONField(
-                        default=dict, editable=False
-                    ),
-                ),
-            ],
-            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,
-            },
-        ),
-    ]
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 382a3e34c36c611ee6cf0b0ab4e4f8876b56181f..04495b37a84c2ce837ebf939b14103a68bc41eea 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -3,7 +3,6 @@ from __future__ import annotations
 from datetime import date, datetime, time, timedelta
 from typing import Dict, Optional, Tuple, Union
 
-from django.contrib.sites.managers import CurrentSiteManager
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.db.models import Max, Min, Q
@@ -21,6 +20,7 @@ from django_global_request.middleware import get_request
 
 from aleksis.apps.chronos.managers import (
     AbsenceQuerySet,
+    CurrentSiteManager,
     EventQuerySet,
     ExtraLessonQuerySet,
     GroupPropertiesMixin,