diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
index aed34488e6cf200f9b1c6c4ae051a845feef0c87..9aa082419edc04af6158e1cb492bb1fb21ca15a4 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
@@ -70,7 +70,10 @@
       </template>
     </infinite-scrolling-date-sorted-c-r-u-d-iterator>
     <v-scale-transition>
-      <absence-creation-dialog v-if="pageType === 'absences'" />
+      <absence-creation-dialog
+        v-if="pageType === 'absences'"
+        :absence-reasons="absenceReasons"
+      />
     </v-scale-transition>
   </div>
 </template>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
index 7a6b4c73f5e3dbe6b6dbfa86df69b96b4a8d74a2..7a4b17c803ac4193f70ef413e913bd4a330c5733 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
@@ -30,6 +30,7 @@
         :end-date="endDate"
         :comment="comment"
         :absence-reason="absenceReason"
+        :absence-reasons="absenceReasons"
         @valid="formValid = $event"
         @persons="persons = $event"
         @start-date="startDate = $event"
@@ -121,6 +122,12 @@ export default {
       absenceReason: "",
     };
   },
+  props: {
+    absenceReasons: {
+      type: Array,
+      required: true,
+    },
+  },
   mounted() {
     this.addPermissions(["alsijil.view_register_absence_rule"]);
     this.clearForm();
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
index 239c83d6bbd48700773c024967636a82f3d3c4a8..74f07cc4dcc9c24ccd42c0c8345182e5e60c6a9b 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
@@ -61,6 +61,7 @@
           <absence-reason-group-select
             :rules="$rules().required.build()"
             :value="absenceReason"
+            :custom-absence-reasons="absenceReasons"
             @input="$emit('absence-reason', $event)"
           />
         </div>
@@ -115,6 +116,10 @@ export default {
       type: String,
       required: true,
     },
+    absenceReasons: {
+      type: Array,
+      required: true,
+    },
   },
   computed: {
     maxStartTime() {
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
deleted file mode 100644
index a86f608ec78d1bbc50bf558b5e0650cba5b5e8a7..0000000000000000000000000000000000000000
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-query absenceReasons($orderBy: [String], $filters: JSONString) {
-  items: coursebookAbsenceReasons(orderBy: $orderBy, filters: $filters) {
-    id
-    shortName
-    name
-    colour
-    default
-    canEdit
-    canDelete
-  }
-}
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
index a49b73f149129fa86e131b804e027908c84f65db..6ae9ba9dae7e2f1de386c9b433f73ae2ae9f3a11 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
@@ -111,7 +111,6 @@ query documentationsForCoursebook(
     oldId
     canEdit
     futureNotice
-    canDelete
     futureNoticeParticipationStatus
     canEditParticipationStatus
     canViewParticipationStatus
diff --git a/aleksis/apps/alsijil/managers.py b/aleksis/apps/alsijil/managers.py
index 983a29b8d73196278afc3de7b1e25f484e62f02f..b8d17a7aa95c34fd7d87314d37da943844a64771 100644
--- a/aleksis/apps/alsijil/managers.py
+++ b/aleksis/apps/alsijil/managers.py
@@ -72,18 +72,6 @@ class GroupRoleAssignmentQuerySet(QuerySet):
 class DocumentationManager(RecurrencePolymorphicManager):
     """Manager adding specific methods to documentations."""
 
-    def get_queryset(self):
-        """Ensure often used related data are loaded as well."""
-        return (
-            super()
-            .get_queryset()
-            .select_related(
-                "course",
-                "subject",
-            )
-            .prefetch_related("teachers")
-        )
-
 
 class ParticipationStatusManager(RecurrencePolymorphicManager):
     """Manager adding specific methods to participation statuses."""
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 7d869c497a9ecbefc699fb1da379af635bd9fe79..9e2d50dead158fcf5f408ffdff59327cda942a01 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -139,7 +139,6 @@ class Documentation(CalendarEvent):
         events: list,
         incomplete: Optional[bool] = False,
         absences_exist: Optional[bool] = False,
-        request: Optional[HttpRequest] = None,
     ) -> tuple:
         """Get all the documentations for the events.
         Create dummy documentations if none exist.
@@ -149,11 +148,22 @@ class Documentation(CalendarEvent):
         dummies = []
 
         # Prefetch existing documentations to speed things up
-        existing_documentations = Documentation.objects.filter(
-            datetime_start__lte=datetime_end,
-            datetime_end__gte=datetime_start,
-            amends__in=[e["REFERENCE_OBJECT"] for e in events],
-        ).prefetch_related("participations")
+        existing_documentations = (
+            Documentation.objects.filter(
+                datetime_start__lte=datetime_end,
+                datetime_end__gte=datetime_start,
+                amends__in=[e["REFERENCE_OBJECT"] for e in events],
+            )
+            .prefetch_related(
+                "participations",
+                "participations__person",
+                "participations__absence_reason",
+                "teachers",
+                "personal_notes",
+                "personal_notes__extra_mark",
+            )
+            .select_related("course", "subject")
+        )
 
         for event in events:
             if incomplete and event["STATUS"] == "CANCELLED":
@@ -179,6 +189,7 @@ class Documentation(CalendarEvent):
                     )
                 ):
                     continue
+                doc._amends_prefetched = event_reference_obj
                 docs.append(doc)
             elif not absences_exist:
                 if event_reference_obj.amends:
@@ -214,7 +225,6 @@ class Documentation(CalendarEvent):
         start: datetime,
         end: datetime,
         incomplete: Optional[bool] = False,
-        request: Optional[HttpRequest] = None,
     ) -> tuple:
         """Get all the documentations for the person from start to end datetime.
         Create dummy documentations if none exist.
@@ -233,7 +243,7 @@ class Documentation(CalendarEvent):
             with_reference_object=True,
         )
 
-        return Documentation.get_documentations_for_events(start, end, events, incomplete, request)
+        return Documentation.get_documentations_for_events(start, end, events, incomplete)
 
     @classmethod
     def parse_dummy(
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index cb0c6b1d16c5dab002794872afd177fa9da1b281..604cda6cd229533086533d855563a892f440d572 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -3,6 +3,7 @@ from datetime import datetime
 from django.db.models import BooleanField, ExpressionWrapper, Q
 
 import graphene
+import graphene_django_optimizer
 
 from aleksis.apps.chronos.models import LessonEvent
 from aleksis.apps.cursus.models import Course
@@ -13,10 +14,15 @@ from aleksis.core.models import Group, Person
 from aleksis.core.schema.base import FilterOrderList
 from aleksis.core.schema.group import GroupType
 from aleksis.core.schema.person import PersonType
-from aleksis.core.util.core_helpers import get_active_school_term, get_site_preferences, has_person
+from aleksis.core.util.core_helpers import (
+    filter_active_school_term,
+    get_active_school_term,
+    get_site_preferences,
+    has_person,
+)
 
 from ..model_extensions import annotate_person_statistics_for_school_term
-from ..models import Documentation, NewPersonalNote, ParticipationStatus
+from ..models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
 from .absences import (
     AbsencesForPersonsCreateMutation,
 )
@@ -47,7 +53,6 @@ from .statistics import StatisticsByPersonType
 
 
 class Query(graphene.ObjectType):
-    documentations = FilterOrderList(DocumentationType)
     documentations_by_course_id = FilterOrderList(
         DocumentationType, course_id=graphene.ID(required=True)
     )
@@ -104,7 +109,7 @@ class Query(graphene.ObjectType):
                 )
             )
         )
-        return documentations
+        return graphene_django_optimizer.query(documentations, info)
 
     def resolve_documentations_for_coursebook(
         root,
@@ -152,6 +157,10 @@ class Query(graphene.ObjectType):
                 }
             )
 
+        school_term = get_active_school_term(info.context)
+        date_start = date_start if date_start > school_term.date_start else school_term.date_start
+        date_end = date_end if date_end < school_term.date_end else school_term.date_end
+
         events = LessonEvent.get_single_events(
             datetime.combine(date_start, datetime.min.time()),
             datetime.combine(date_end, datetime.max.time()),
@@ -167,7 +176,6 @@ class Query(graphene.ObjectType):
             events,
             incomplete,
             absences_exist,
-            info.context,
         )
         return docs + dummies
 
@@ -182,8 +190,10 @@ class Query(graphene.ObjectType):
         else:
             return []
 
+        school_term = get_active_school_term(info.context)
+
         return (
-            Group.objects.for_current_school_term_or_all()
+            Group.objects.for_school_term(school_term)
             .filter(
                 pk__in=Group.objects.filter(members=person)
                 .values_list("id", flat=True)
@@ -211,6 +221,9 @@ class Query(graphene.ObjectType):
             person = info.context.user.person
         else:
             return []
+
+        school_term = get_active_school_term(info.context)
+
         return Course.objects.filter(
             pk__in=(
                 Course.objects.filter(teachers=person)
@@ -223,20 +236,22 @@ class Query(graphene.ObjectType):
                     )
                 )
             )
-        ).filter(groups__in=Group.objects.for_current_school_term_or_all())
+        ).filter(groups__in=Group.objects.for_school_term(school_term))
 
     @staticmethod
     def resolve_absence_creation_persons(root, info, **kwargs):
         if not info.context.user.has_perm("alsijil.register_absence"):
             group_types = get_site_preferences()["alsijil__group_types_register_absence"]
+            school_term = get_active_school_term(info.context)
             if group_types:
                 return Person.objects.filter(
-                    member_of__in=Group.objects.filter(
+                    member_of__in=Group.objects.for_school_term(school_term).filter(
                         owners=info.context.user.person, group_type__in=group_types
                     )
                 )
             else:
-                return Person.objects.filter(member_of__owners=info.context.user.person)
+                qs = Person.objects.filter(member_of__owners=info.context.user.person)
+                return filter_active_school_term(info.context, qs, "member_of__school_term")
         return Person.objects.all()
 
     @staticmethod
@@ -255,13 +270,18 @@ class Query(graphene.ObjectType):
                 person,
                 start,
                 end,
-                info.context,
             )
 
             lessons_for_person.append(LessonsForPersonType(id=person, lessons=docs + dummies))
 
         return lessons_for_person
 
+    @staticmethod
+    def resolve_extra_marks(root, info, **kwargs):
+        if info.context.user.has_perm("alsijil.fetch_extramarks_rule"):
+            return ExtraMark.objects.all()
+        raise []
+
     @staticmethod
     def resolve_coursebook_absence_reasons(root, info, **kwargs):
         if not info.context.user.has_perm("kolego.fetch_absencereasons_rule"):
@@ -274,9 +294,12 @@ class Query(graphene.ObjectType):
         if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
             return None
         school_term = get_active_school_term(info.context)
-        return annotate_person_statistics_for_school_term(
-            Person.objects.filter(id=person.id), school_term
-        ).first()
+        return graphene_django_optimizer.query(
+            annotate_person_statistics_for_school_term(
+                Person.objects.filter(id=person.id), school_term
+            ).first(),
+            info,
+        )
 
     @staticmethod
     def resolve_participations_of_person(root, info, person):
@@ -284,12 +307,15 @@ class Query(graphene.ObjectType):
         if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
             return []
         school_term = get_active_school_term(info.context)
-        return ParticipationStatus.objects.filter(
-            person=person,
-            absence_reason__isnull=False,
-            datetime_start__date__gte=school_term.date_start,
-            datetime_end__date__lte=school_term.date_end,
-        ).order_by("-related_documentation__datetime_start")
+        return graphene_django_optimizer.query(
+            ParticipationStatus.objects.filter(
+                person=person,
+                absence_reason__isnull=False,
+                datetime_start__date__gte=school_term.date_start,
+                datetime_end__date__lte=school_term.date_end,
+            ).order_by("-related_documentation__datetime_start"),
+            info,
+        )
 
     @staticmethod
     def resolve_personal_notes_for_person(root, info, person):
@@ -297,13 +323,16 @@ class Query(graphene.ObjectType):
         if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
             return []
         school_term = get_active_school_term(info.context)
-        return NewPersonalNote.objects.filter(
-            person=person,
-            documentation__in=Documentation.objects.filter(
-                datetime_start__date__gte=school_term.date_start,
-                datetime_end__date__lte=school_term.date_end,
-            ),
-        ).order_by("-documentation__datetime_start")
+        return graphene_django_optimizer.query(
+            NewPersonalNote.objects.filter(
+                person=person,
+                documentation__in=Documentation.objects.filter(
+                    datetime_start__date__gte=school_term.date_start,
+                    datetime_end__date__lte=school_term.date_end,
+                ),
+            ).order_by("-documentation__datetime_start"),
+            info,
+        )
 
     @staticmethod
     def resolve_statistics_by_group(root, info, group):
@@ -313,7 +342,9 @@ class Query(graphene.ObjectType):
         school_term = get_active_school_term(info.context)
 
         members = group.members.all()
-        return annotate_person_statistics_for_school_term(members, school_term, group=group)
+        return graphene_django_optimizer.query(
+            annotate_person_statistics_for_school_term(members, school_term, group=group), info
+        )
 
 
 class Mutation(graphene.ObjectType):
diff --git a/aleksis/apps/alsijil/schema/documentation.py b/aleksis/apps/alsijil/schema/documentation.py
index b833de336b2a2add64ac5f0e0cf6dd7fdd8ae0c5..6b0c3e1ffb0c7a328eadb159c9407c5f8a2d74fa 100644
--- a/aleksis/apps/alsijil/schema/documentation.py
+++ b/aleksis/apps/alsijil/schema/documentation.py
@@ -1,6 +1,7 @@
 from django.core.exceptions import PermissionDenied
 
 import graphene
+from graphene_django import bypass_get_queryset
 from graphene_django.types import DjangoObjectType
 from reversion import create_revision, set_comment, set_user
 
@@ -32,7 +33,6 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
         fields = (
             "id",
             "course",
-            "amends",
             "subject",
             "topic",
             "homework",
@@ -62,6 +62,14 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
     old_id = graphene.ID(required=False)
 
     @staticmethod
+    @bypass_get_queryset
+    def resolve_amends(root: Documentation, info, **kwargs):
+        if hasattr(root, "_amends_prefetched"):
+            return root._amends_prefetched
+        return root.amends
+
+    @staticmethod
+    @bypass_get_queryset
     def resolve_teachers(root: Documentation, info, **kwargs):
         if not str(root.pk).startswith("DUMMY") and hasattr(root, "teachers"):
             return root.teachers
@@ -100,6 +108,7 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
         )
 
     @staticmethod
+    @bypass_get_queryset
     def resolve_participations(root: Documentation, info, **kwargs):
         # A dummy documentation will not have any participations
         if str(root.pk).startswith("DUMMY") or not hasattr(root, "participations"):
@@ -112,6 +121,11 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
                     p for p in root.participations.all() if p.person == info.context.user.person
                 ]
             return []
+
+        # Annotate participations with prefetched documentation data for personal notes
+        for participation in root.participations.all():
+            participation._prefetched_documentation = root
+
         return root.participations.all()
 
 
diff --git a/aleksis/apps/alsijil/schema/extra_marks.py b/aleksis/apps/alsijil/schema/extra_marks.py
index 2b1e3723d2c559e70ddd6793f5f2a89d9c1e6abe..be062b7ed3248a6836c45ee0d4d75616ed65fa54 100644
--- a/aleksis/apps/alsijil/schema/extra_marks.py
+++ b/aleksis/apps/alsijil/schema/extra_marks.py
@@ -23,12 +23,6 @@ class ExtraMarkType(
         model = ExtraMark
         fields = ("id", "short_name", "name", "colour_fg", "colour_bg", "show_in_coursebook")
 
-    @classmethod
-    def get_queryset(cls, queryset, info):
-        if info.context.user.has_perm("alsijil.fetch_extramarks_rule"):
-            return queryset
-        raise PermissionDenied()
-
 
 class ExtraMarkBatchCreateMutation(BaseBatchCreateMutation):
     class Meta:
diff --git a/aleksis/apps/alsijil/schema/participation_status.py b/aleksis/apps/alsijil/schema/participation_status.py
index 22e5820594994b2d1bb4c81ae4f5a83f615bea0b..bb0e24e0564ab5f87a3fe1a25c85f4d8c5766241 100644
--- a/aleksis/apps/alsijil/schema/participation_status.py
+++ b/aleksis/apps/alsijil/schema/participation_status.py
@@ -41,6 +41,12 @@ class ParticipationStatusType(
 
     @staticmethod
     def resolve_notes_with_extra_mark(root: ParticipationStatus, info, **kwargs):
+        if hasattr(root, "_prefetched_documentation"):
+            return [
+                p
+                for p in root._prefetched_documentation.personal_notes.all()
+                if p.person_id == root.person_id and p.extra_mark
+            ]
         return NewPersonalNote.objects.filter(
             person=root.person,
             documentation=root.related_documentation,
@@ -49,6 +55,12 @@ class ParticipationStatusType(
 
     @staticmethod
     def resolve_notes_with_note(root: ParticipationStatus, info, **kwargs):
+        if hasattr(root, "_prefetched_documentation"):
+            return [
+                p
+                for p in root._prefetched_documentation.personal_notes.all()
+                if p.person_id == root.person_id and p.note
+            ]
         return NewPersonalNote.objects.filter(
             person=root.person,
             documentation=root.related_documentation,