diff --git a/aleksis/apps/alsijil/managers.py b/aleksis/apps/alsijil/managers.py
new file mode 100644
index 0000000000000000000000000000000000000000..b2589345adac4c2c02159ea54fc872fe9055408a
--- /dev/null
+++ b/aleksis/apps/alsijil/managers.py
@@ -0,0 +1,23 @@
+from aleksis.core.managers import CurrentSiteManagerWithoutMigrations
+
+
+class PersonalNoteManager(CurrentSiteManagerWithoutMigrations):
+    """Manager adding specific methods to personal notes."""
+
+    def get_queryset(self):
+        """Ensure all related lesson and person data are loaded as well."""
+        return (
+            super()
+            .get_queryset()
+            .select_related(
+                "person",
+                "excuse_type",
+                "lesson_period",
+                "lesson_period__lesson",
+                "lesson_period__lesson__subject",
+                "lesson_period__period",
+                "lesson_period__lesson__validity",
+                "lesson_period__lesson__validity__school_term",
+            )
+            .prefetch_related("extra_marks")
+        )
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index b688332997fcc890dd719467c8997cae403758bd..7881eb9f995d8d59be15af19833cb0edda07e096 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -1,5 +1,5 @@
 from datetime import date
-from typing import Dict, Optional, Union
+from typing import Dict, Iterator, Optional, Union
 
 from django.db.models import Exists, OuterRef, Q, QuerySet
 from django.db.models.aggregates import Count
@@ -176,11 +176,14 @@ def get_lesson_documentation(
     """Get lesson documentation object for this lesson."""
     if not week:
         week = self.week
+    # Use all to make effect of prefetched data
+    doc_filter = filter(
+        lambda d: d.week == week.week and d.year == week.year,
+        self.dopycumentations.all(),
+    )
     try:
-        return LessonDocumentation.objects.get(
-            lesson_period=self, week=week.week, year=week.year
-        )
-    except LessonDocumentation.DoesNotExist:
+        return next(doc_filter)
+    except StopIteration:
         return None
 
 
@@ -198,11 +201,15 @@ def get_or_create_lesson_documentation(
 
 
 @LessonPeriod.method
-def get_absences(self, week: Optional[CalendarWeek] = None) -> QuerySet:
+def get_absences(self, week: Optional[CalendarWeek] = None) -> Iterator:
     """Get all personal notes of absent persons for this lesson."""
     if not week:
         week = self.week
-    return self.personal_notes.filter(week=week.week, year=week.year, absent=True)
+
+    return filter(
+        lambda p: p.week == week.week and p.year == week.year and p.absent,
+        self.personal_notes.all(),
+    )
 
 
 @LessonPeriod.method
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 66f6477d22165c085abd0855502686d505d75c75..e2f234a596275f57c4427f916144f534f9092adf 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -1,9 +1,12 @@
 from django.db import models
 from django.utils.formats import date_format
+from django.utils.functional import classproperty
 from django.utils.translation import gettext_lazy as _
 
+from cache_memoize import cache_memoize
 from calendarweek import CalendarWeek
 
+from aleksis.apps.alsijil.managers import PersonalNoteManager
 from aleksis.apps.chronos.mixins import WeekRelatedMixin
 from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.apps.chronos.util.date import get_current_year
@@ -46,6 +49,8 @@ class PersonalNote(ExtensibleModel, WeekRelatedMixin):
     and remarks about a student in a single lesson period.
     """
 
+    objects = PersonalNoteManager()
+
     person = models.ForeignKey(
         "core.Person", models.CASCADE, related_name="personal_notes"
     )
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index 8ee92ec5eb2f53b472e0b873995a3522d54c6d32..cb2bda3333471b171a0e76010c574fb22843fdbc 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -29,11 +29,11 @@ from .util.predicates import (
 
 # View lesson
 view_lesson_predicate = has_person & (
-    has_global_perm("alsijil.view_lesson")
-    | is_none  # View is opened as "Current lesson"
+    is_none  # View is opened as "Current lesson"
     | is_lesson_teacher
     | is_lesson_participant
     | is_lesson_parent_group_owner
+    | has_global_perm("alsijil.view_lesson")
     | has_lesson_group_object_perm("core.view_week_class_register_group")
 )
 add_perm("alsijil.view_lesson", view_lesson_predicate)
@@ -43,37 +43,37 @@ add_perm("alsijil.view_lesson_menu", has_person)
 
 # View lesson personal notes
 view_lesson_personal_notes_predicate = view_lesson_predicate & (
-    has_global_perm("alsijil.view_personalnote")
-    | ~is_lesson_participant
+    ~is_lesson_participant
+    | has_global_perm("alsijil.view_personalnote")
     | has_lesson_group_object_perm("core.view_personalnote_group")
 )
 add_perm("alsijil.view_lesson_personalnote", view_lesson_personal_notes_predicate)
 
 # Edit personal note
 edit_lesson_personal_note_predicate = view_lesson_personal_notes_predicate & (
-    has_global_perm("alsijil.change_personalnote")
-    | ~is_lesson_parent_group_owner
+    ~is_lesson_parent_group_owner
+    | has_global_perm("alsijil.change_personalnote")
     | has_lesson_group_object_perm("core.edit_personalnote_group")
 )
 add_perm("alsijil.edit_lesson_personalnote", edit_lesson_personal_note_predicate)
 
 # View personal note
 view_personal_note_predicate = has_person & (
-    has_global_perm("alsijil.view_personalnote")
-    | is_personal_note_lesson_teacher
-    | (
+    (
         is_own_personal_note
         & is_site_preference_set("alsijil", "view_own_personal_notes")
     )
+    | is_personal_note_lesson_teacher
     | is_personal_note_lesson_parent_group_owner
+    | has_global_perm("alsijil.view_personalnote")
     | has_personal_note_group_perm("core.view_personalnote_group")
 )
 add_perm("alsijil.view_personalnote", view_personal_note_predicate)
 
 # Edit personal note
 edit_personal_note_predicate = view_personal_note_predicate & (
-    has_global_perm("alsijil.view_personalnote")
-    | ~is_own_personal_note
+    ~is_own_personal_note
+    | has_global_perm("alsijil.view_personalnote")
     | has_personal_note_group_perm("core.edit_personalnote_group")
 )
 add_perm("alsijil.edit_personalnote", edit_personal_note_predicate)
@@ -84,18 +84,18 @@ add_perm("alsijil.view_lessondocumentation", view_lesson_documentation_predicate
 
 # Edit lesson documentation
 edit_lesson_documentation_predicate = view_lesson_predicate & (
-    has_global_perm("alsijil.change_lessondocumentation")
-    | is_lesson_teacher
+    is_lesson_teacher
+    | has_global_perm("alsijil.change_lessondocumentation")
     | has_lesson_group_object_perm("core.edit_lessondocumentation_group")
 )
 add_perm("alsijil.edit_lessondocumentation", edit_lesson_documentation_predicate)
 
 # View week overview
 view_week_predicate = has_person & (
-    has_global_perm("alsijil.view_week")
-    | is_current_person
+    is_current_person
     | is_group_member
     | is_group_owner
+    | has_global_perm("alsijil.view_week")
     | has_object_perm("core.view_week_class_register_group")
 )
 add_perm("alsijil.view_week", view_week_predicate)
@@ -105,10 +105,10 @@ add_perm("alsijil.view_week_menu", has_person)
 
 # View week personal notes
 view_week_personal_notes_predicate = has_person & (
-    has_global_perm("alsijil.view_personalnote")
-    | has_object_perm("core.view_personalnote_group")
+    (is_current_person & is_teacher)
     | is_group_owner
-    | (is_current_person & is_teacher)
+    | has_global_perm("alsijil.view_personalnote")
+    | has_object_perm("core.view_personalnote_group")
 )
 add_perm("alsijil.view_week_personalnote", view_week_personal_notes_predicate)
 
@@ -120,21 +120,21 @@ add_perm("alsijil.view_register_absence", view_register_absence_predicate)
 
 # Register absence
 register_absence_predicate = has_person & (
-    has_global_perm("alsijil.register_absence")
-    | has_person_group_object_perm("core.register_absence_group")
-    | has_object_perm("core.register_absence_person")
-    | (
+    (
         is_person_primary_group_owner
         & is_site_preference_set("alsijil", "register_absence_as_primary_group_owner")
     )
+    | has_global_perm("alsijil.register_absence")
+    | has_object_perm("core.register_absence_person")
+    | has_person_group_object_perm("core.register_absence_group")
 )
 add_perm("alsijil.register_absence", register_absence_predicate)
 
 # View full register for group
 view_full_register_predicate = has_person & (
-    has_global_perm("alsijil.view_full_register")
+    is_group_owner
+    | has_global_perm("alsijil.view_full_register")
     | has_object_perm("core.view_full_register_group")
-    | is_group_owner
 )
 add_perm("alsijil.view_full_register", view_full_register_predicate)
 
@@ -159,10 +159,10 @@ add_perm("alsijil.view_person_overview_menu", view_person_overview_menu_predicat
 
 # View person overview personal notes
 view_person_overview_personal_notes_predicate = view_person_overview_predicate & (
-    has_global_perm("alsijil.view_personalnote")
-    | has_person_group_object_perm("core.view_personalnote_group")
+    (is_current_person & is_site_preference_set("alsijil", "view_own_personal_notes"))
     | is_person_primary_group_owner
-    | (is_current_person & is_site_preference_set("alsijil", "view_own_personal_notes"))
+    | has_global_perm("alsijil.view_personalnote")
+    | has_person_group_object_perm("core.view_personalnote_group")
 )
 add_perm(
     "alsijil.view_person_overview_personalnote",
@@ -173,8 +173,8 @@ add_perm(
 edit_person_overview_personal_notes_predicate = (
     view_person_overview_personal_notes_predicate
     & (
-        has_global_perm("alsijil.edit_personalnote")
-        | ~is_current_person
+        ~is_current_person
+        | has_global_perm("alsijil.edit_personalnote")
         | has_person_group_object_perm("core.edit_personalnote_group")
     )
 )
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
index 19dfebb0b8874746824ce9ffba840920dc8e2e3d..5f8ba67a9904999b8be2ed74f0f454f8ad28e54c 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
@@ -12,7 +12,7 @@
 {% block page_title %}
   {% with lesson_period.get_lesson_documentation as lesson_doc %}
     <a href="{% url "week_view_by_week" lesson_doc.year lesson_doc.week "group" lesson_period.lesson.groups.all.0.pk %}"
-    class="btn-flat primary-color-text waves-light waves-effect">
+       class="btn-flat primary-color-text waves-light waves-effect">
       <i class="material-icons left">chevron_left</i> {% trans "Back" %}
     </a>
   {% endwith %}
@@ -40,21 +40,17 @@
 
   <div class="row">
     <div class="col s12">
-      {% with prev_lesson=lesson_period.prev %}
-        <a class="btn-flat left waves-effect waves-light"
-           href="{% url "lesson_by_week_and_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}">
-          <i class="material-icons left">arrow_back</i>
-          {% trans "Previous lesson" %}
-        </a>
-      {% endwith %}
+      <a class="btn-flat left waves-effect waves-light"
+         href="{% url "lesson_by_week_and_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}">
+        <i class="material-icons left">arrow_back</i>
+        {% trans "Previous lesson" %}
+      </a>
 
-      {% with next_lesson=lesson_period.next %}
-        <a class="btn-flat right waves-effect waves-light"
-           href="{% url "lesson_by_week_and_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}">
-          <i class="material-icons right">arrow_forward</i>
-          {% trans "Next lesson" %}
-        </a>
-      {% endwith %}
+      <a class="btn-flat right waves-effect waves-light"
+         href="{% url "lesson_by_week_and_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}">
+        <i class="material-icons right">arrow_forward</i>
+        {% trans "Next lesson" %}
+      </a>
     </div>
   </div>
 
@@ -130,75 +126,74 @@
       </div>
 
       {% with prev_lesson=lesson_period.prev prev_doc=prev_lesson.get_lesson_documentation %}
-          {% with prev_doc=prev_lesson.get_lesson_documentation absences=prev_lesson.get_absences tardinesses=prev_lesson.get_tardinesses extra_marks=prev_lesson.get_extra_marks %}
-            {% has_perm "alsijil.view_lessondocumentation" user prev_lesson as can_view_prev_lesson_documentation %}
-            {% if prev_doc and can_view_prev_lesson_documentation %}
-              {% weekday_to_date prev_lesson.week prev_lesson.period.weekday as prev_date %}
-              <div class="col s12" id="previous-lesson">
-              <div class="card">
-                <div class="card-content">
+        {% with absences=prev_lesson.get_absences tardinesses=prev_lesson.get_tardinesses extra_marks=prev_lesson.get_extra_marks %}
+          {% has_perm "alsijil.view_lessondocumentation" user prev_lesson as can_view_prev_lesson_documentation %}
+          {% if prev_doc and can_view_prev_lesson_documentation %}
+            {% weekday_to_date prev_lesson.week prev_lesson.period.weekday as prev_date %}
+            <div class="col s12" id="previous-lesson">
+            <div class="card">
+              <div class="card-content">
                   <span class="card-title">
                     {% blocktrans %}Overview: Previous lesson{% endblocktrans %} ({{ prev_date }},
                     {% blocktrans with period=prev_lesson.period.period %}{{ period }}. period{% endblocktrans %})
                   </span>
 
-                  <table>
-                    {% if prev_doc.topic %}
-                      <tr>
-                        <th class="collection-item">{% trans "Lesson topic of previous lesson:" %}</th>
-                        <td>{{ prev_doc.topic }}</td>
-                      </tr>
-                    {% endif %}
+                <table>
+                  {% if prev_doc.topic %}
+                    <tr>
+                      <th class="collection-item">{% trans "Lesson topic of previous lesson:" %}</th>
+                      <td>{{ prev_doc.topic }}</td>
+                    </tr>
+                  {% endif %}
 
-                    {% if prev_doc.homework %}
-                      <tr>
-                        <th class="collection-item">{% trans "Homework for this lesson:" %}</th>
-                        <td>{{ prev_doc.homework }}</td>
-                      </tr>
-                    {% endif %}
+                  {% if prev_doc.homework %}
+                    <tr>
+                      <th class="collection-item">{% trans "Homework for this lesson:" %}</th>
+                      <td>{{ prev_doc.homework }}</td>
+                    </tr>
+                  {% endif %}
 
-                    {% if prev_doc.group_note %}
-                      <tr>
-                        <th class="collection-item">{% trans "Group notes for previous lesson:" %}</th>
-                        <td>{{ prev_doc.group_note }}</td>
-                      </tr>
-                    {% endif %}
+                  {% if prev_doc.group_note %}
+                    <tr>
+                      <th class="collection-item">{% trans "Group notes for previous lesson:" %}</th>
+                      <td>{{ prev_doc.group_note }}</td>
+                    </tr>
+                  {% endif %}
 
-                    {% if absences %}
-                      <tr>
-                        <th>{% trans "Absent persons:" %}</th>
-                        <td>{% include "alsijil/partials/absences.html" with notes=absences %}</td>
-                      </tr>
-                    {% endif %}
+                  {% if absences %}
+                    <tr>
+                      <th>{% trans "Absent persons:" %}</th>
+                      <td>{% include "alsijil/partials/absences.html" with notes=absences %}</td>
+                    </tr>
+                  {% endif %}
 
-                    {% if tardinesses %}
-                      <tr>
-                        <th>{% trans "Late persons:" %}</th>
-                        <td>{% include "alsijil/partials/tardinesses.html" with notes=tardinesses %}</td>
-                      </tr>
-                    {% endif %}
+                  {% if tardinesses %}
+                    <tr>
+                      <th>{% trans "Late persons:" %}</th>
+                      <td>{% include "alsijil/partials/tardinesses.html" with notes=tardinesses %}</td>
+                    </tr>
+                  {% endif %}
 
-                    {% for extra_mark, notes in extra_marks.items %}
-                      <tr>
-                        <th>{{ extra_mark.name }}</th>
-                        <td>
-                          {% for note in notes %}
-                            {% has_perm "alsijil.view_personalnote" user note as can_view_personalnote %}
-                            {% if can_view_personalnote %}
-                              <span>{{ note.person }}{% if not forloop.last %},{% endif %}</span>
-                            {% endif %}
-                          {% endfor %}
-                        </td>
-                      </tr>
-                    {% endfor %}
+                  {% for extra_mark, notes in extra_marks.items %}
+                    <tr>
+                      <th>{{ extra_mark.name }}</th>
+                      <td>
+                        {% for note in notes %}
+                          {% has_perm "alsijil.view_personalnote" user note as can_view_personalnote %}
+                          {% if can_view_personalnote %}
+                            <span>{{ note.person }}{% if not forloop.last %},{% endif %}</span>
+                          {% endif %}
+                        {% endfor %}
+                      </td>
+                    </tr>
+                  {% endfor %}
 
-                  </table>
-                </div>
-              </div>
+                </table>
               </div>
-            {% endif %}
-          {% endwith %}
+            </div>
+          {% endif %}
         {% endwith %}
+      {% endwith %}
 
       {% if not lesson_period.get_substitution.cancelled or not request.site.preferences.alsijil__block_personal_notes_for_cancelled %}
         <div class="col s12" id="personal-notes">
@@ -284,8 +279,8 @@
                       <td>{{ form.person_name.value }}</td>
                       <td><i class="material-icons center">{{ form.absent.value|yesno:"check,clear" }}</i></td>
                       <td>
-                          <i class="material-icons center">{{ form.late.value|yesno:"check,clear" }}</i>
-                          <span class="alsijil-tardiness-text">
+                        <i class="material-icons center">{{ form.late.value|yesno:"check,clear" }}</i>
+                        <span class="alsijil-tardiness-text">
                             {% if form.late.value %}{{ form.late.value|to_time|time:"i\m" }}{% endif %}
                           </span>
                       </td>
@@ -321,10 +316,10 @@
           </div>
         </div>
       {% endif %}
-    </div>
+      </div>
 
-    {% if can_edit_lesson_documentation or can_edit_lesson_personalnote %}
-      <p>{% include "core/partials/save_button.html" %}</p>
-    {% endif %}
+      {% if can_edit_lesson_documentation or can_edit_lesson_personalnote %}
+        <p>{% include "core/partials/save_button.html" %}</p>
+      {% endif %}
   </form>
 {% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
index 03b75de7b70508885bf06f35e42d1058a5c80b1a..6820996b7370426869a37a054a58d5faf77aa0a6 100644
--- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
@@ -175,7 +175,7 @@
       </thead>
 
       <tbody>
-      {% for lesson in group.lessons.all %}
+      {% for lesson in lessons %}
         <tr>
           <td>{{ lesson.subject.name }}</td>
           <td>{{ lesson.teachers.all|join:', ' }}</td>
@@ -206,7 +206,7 @@
       </thead>
 
       <tbody>
-      {% for child_group in group.child_groups.all %}
+      {% for child_group in child_groups %}
         {% for lesson in child_group.lessons.all %}
           <tr>
             <td>{{ child_group.name }}</td>
diff --git a/aleksis/apps/alsijil/templatetags/time_helpers.py b/aleksis/apps/alsijil/templatetags/time_helpers.py
index 00aedad7fee98b2b0d303f63f927fbe722317651..cae2ee2e35ef5c25c338b617b784508185d669e8 100644
--- a/aleksis/apps/alsijil/templatetags/time_helpers.py
+++ b/aleksis/apps/alsijil/templatetags/time_helpers.py
@@ -1,7 +1,7 @@
-from django import template
-
 import datetime
 
+from django import template
+
 register = template.Library()
 
 
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index 3d988c8f4c3134b46451d04b24a570177473c44a..4bdd2a34ca1bf7ed1e81777e4f99e493d071905c 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -1,12 +1,14 @@
 from typing import Any, Union
 
-from django.contrib.auth.models import User
+from django.contrib.auth.models import Permission, User
 
+from guardian.models import UserObjectPermission
 from guardian.shortcuts import get_objects_for_user
 from rules import predicate
 
 from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.core.models import Group, Person
+from aleksis.core.util.core_helpers import get_content_type_by_perm, get_site_preferences
 from aleksis.core.util.predicates import check_object_permission
 
 from ..models import PersonalNote
@@ -41,7 +43,9 @@ def is_lesson_participant(user: User, obj: LessonPeriod) -> bool:
     the groups linked to the given LessonPeriod.
     """
     if hasattr(obj, "lesson"):
-        return obj.lesson.groups.filter(members=user.person).exists()
+        for group in obj.lesson.groups.all():
+            if user.person in list(group.members.all()):
+                return True
     return False
 
 
@@ -54,7 +58,10 @@ def is_lesson_parent_group_owner(user: User, obj: LessonPeriod) -> bool:
     any parent groups of any groups of the given LessonPeriods lesson.
     """
     if hasattr(obj, "lesson"):
-        return obj.lesson.groups.filter(parent_groups__owners=user.person).exists()
+        for group in obj.lesson.groups.all():
+            for parent_group in group.parent_groups.all():
+                if user.person in list(parent_group.owners.all()):
+                    return True
     return False
 
 
@@ -66,7 +73,7 @@ def is_group_owner(user: User, obj: Union[Group, Person]) -> bool:
     If there isn't provided a group, it will return `False`.
     """
     if isinstance(obj, Group):
-        if obj.owners.filter(pk=user.person.pk).exists():
+        if user.person in obj.owners.all():
             return True
 
     return False
@@ -81,7 +88,10 @@ def is_person_group_owner(user: User, obj: Person) -> bool:
     the owner of any group of the given person.
     """
     if obj:
-        return obj.member_of.filter(owners=user.person).exists()
+        for group in obj.member_of.all():
+            if user.person in list(group.owners.all()):
+                return True
+        return False
     return False
 
 
@@ -105,12 +115,19 @@ def has_person_group_object_perm(perm: str):
     """
     name = f"has_person_group_object_perm:{perm}"
 
+    ct = get_content_type_by_perm(perm)
+    permissions = Permission.objects.filter(content_type=ct, codename=perm)
+
     @predicate(name)
     def fn(user: User, obj: Person) -> bool:
-        for group in obj.member_of.all():
-            if check_object_permission(user, perm, group):
-                return True
-        return False
+        groups = obj.member_of.all()
+        qs = UserObjectPermission.objects.filter(
+            object_pk__in=list(groups.values_list("pk", flat=True)),
+            content_type=ct,
+            user=user,
+            permission__in=permissions,
+        )
+        return qs.exists()
 
     return fn
 
@@ -123,7 +140,7 @@ def is_group_member(user: User, obj: Union[Group, Person]) -> bool:
     If there isn't provided a group, it will return `False`.
     """
     if isinstance(obj, Group):
-        if obj.members.filter(pk=user.person.pk).exists():
+        if user.person in obj.members.all():
             return True
 
     return False
@@ -136,14 +153,21 @@ def has_lesson_group_object_perm(perm: str):
     """
     name = f"has_lesson_group_object_perm:{perm}"
 
+    ct = get_content_type_by_perm(perm)
+    permissions = Permission.objects.filter(content_type=ct, codename=perm)
+
     @predicate(name)
     def fn(user: User, obj: LessonPeriod) -> bool:
         if hasattr(obj, "lesson"):
-            for group in obj.lesson.groups.all():
-                if check_object_permission(user, perm, group):
-                    return True
-            return False
-        return True
+            groups = obj.lesson.groups.all()
+            qs = UserObjectPermission.objects.filter(
+                object_pk__in=list(groups.values_list("pk", flat=True)),
+                content_type=ct,
+                user=user,
+                permission__in=permissions,
+            )
+            return qs.exists()
+        return False
 
     return fn
 
@@ -155,13 +179,21 @@ def has_personal_note_group_perm(perm: str):
     """
     name = f"has_personal_note_person_or_group_perm:{perm}"
 
+    ct = get_content_type_by_perm(perm)
+    permissions = Permission.objects.filter(content_type=ct, codename=perm)
+
     @predicate(name)
     def fn(user: User, obj: PersonalNote) -> bool:
         if hasattr(obj, "person"):
-            for group in obj.person.member_of.all():
-                if check_object_permission(user, perm, group):
-                    return True
-            return False
+            groups = obj.person.member_of.all()
+            qs = UserObjectPermission.objects.filter(
+                object_pk__in=list(groups.values_list("pk", flat=True)),
+                content_type=ct,
+                user=user,
+                permission__in=permissions,
+            )
+            return qs.exists()
+        return False
 
     return fn
 
@@ -208,10 +240,10 @@ def is_personal_note_lesson_parent_group_owner(user: User, obj: PersonalNote) ->
     """
     if hasattr(obj, "lesson_period"):
         if hasattr(obj.lesson_period, "lesson"):
-            return obj.lesson_period.lesson.groups.filter(
-                parent_groups__owners=user.person
-            ).exists()
-        return False
+            for group in obj.lesson_period.lesson.groups.all():
+                for parent_group in group.parent_groups.all():
+                    if user.person in list(parent_group.owners.all()):
+                        return True
     return False
 
 
@@ -220,10 +252,10 @@ def has_any_object_absence(user: User) -> bool:
     """
     Predicate which builds a query with all the persons the given users is allowed to register an absence for.
     """
-    if get_objects_for_user(user, "core.register_absence_person", Person).exists():
-        return True
     if Person.objects.filter(member_of__owners=user.person).exists():
         return True
+    if get_objects_for_user(user, "core.register_absence_person", Person).exists():
+        return True
     if Person.objects.filter(
         member_of__in=get_objects_for_user(user, "core.register_absence_group", Group)
     ).exists():
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 6120e8dca3e0ba06bc0d93ed05c1b11adee003c7..d72c5856334a31b78c2cfca6630fef2416f13027 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta
 from typing import Optional
 
 from django.core.exceptions import PermissionDenied
-from django.db.models import Count, Exists, OuterRef, Q, Subquery, Sum
+from django.db.models import Count, Exists, OuterRef, Prefetch, Q, Subquery, Sum
 from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse, reverse_lazy
@@ -16,7 +16,7 @@ from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin, permission_required
 
 from aleksis.apps.chronos.managers import TimetableType
-from aleksis.apps.chronos.models import LessonPeriod, TimePeriod
+from aleksis.apps.chronos.models import LessonPeriod, LessonSubstitution, TimePeriod
 from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
 from aleksis.apps.chronos.util.date import get_weeks_for_year, week_weekday_to_date
 from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
@@ -158,6 +158,8 @@ def lesson(
     context["lesson_documentation"] = lesson_documentation
     context["lesson_documentation_form"] = lesson_documentation_form
     context["personal_note_formset"] = personal_note_formset
+    context["prev_lesson"] = lesson_period.prev
+    context["next_lesson"] = lesson_period.next
 
     return render(request, "alsijil/class_register/lesson.html", context)
 
@@ -179,17 +181,13 @@ def week_view(
 
     instance = get_timetable_instance_by_pk(request, year, week, type_, id_)
 
-    lesson_periods = LessonPeriod.objects.in_week(wanted_week).annotate(
-        has_documentation=Exists(
-            LessonDocumentation.objects.filter(
-                ~Q(topic__exact=""),
-                lesson_period=OuterRef("pk"),
-                week=wanted_week.week,
-                year=wanted_week.year,
-            )
-        )
+    lesson_periods = LessonPeriod.objects.in_week(wanted_week).prefetch_related(
+        "lesson__groups__members",
+        "lesson__groups__parent_groups",
+        "lesson__groups__parent_groups__owners",
     )
 
+    lesson_periods_query_exists = True
     if type_ and id_:
         if isinstance(instance, HttpResponseNotFound):
             return HttpResponseNotFound()
@@ -204,6 +202,7 @@ def week_view(
         else:
             lesson_periods = lesson_periods.filter_participant(request.user.person)
     else:
+        lesson_periods_query_exists = False
         lesson_periods = None
 
     # Add a form to filter the view
@@ -231,10 +230,38 @@ def week_view(
     else:
         group = None
 
-    if lesson_periods:
-        # Aggregate all personal notes for this group and week
+    extra_marks = ExtraMark.objects.all()
+
+    if lesson_periods_query_exists:
         lesson_periods_pk = list(lesson_periods.values_list("pk", flat=True))
+        lesson_periods = (
+            LessonPeriod.objects.prefetch_related(
+                Prefetch(
+                    "documentations",
+                    queryset=LessonDocumentation.objects.filter(
+                        week=wanted_week.week, year=wanted_week.year
+                    ),
+                )
+            )
+            .filter(pk__in=lesson_periods_pk)
+            .annotate_week(wanted_week)
+            .annotate(
+                has_documentation=Exists(
+                    LessonDocumentation.objects.filter(
+                        ~Q(topic__exact=""),
+                        lesson_period=OuterRef("pk"),
+                        week=wanted_week.week,
+                        year=wanted_week.year,
+                    )
+                )
+            )
+            .order_by("period__weekday", "period__period")
+        )
+    else:
+        lesson_periods_pk = []
 
+    if lesson_periods_pk:
+        # Aggregate all personal notes for this group and week
         persons_qs = Person.objects.filter(is_active=True)
 
         if not request.user.has_perm("alsijil.view_week_personalnote", instance):
@@ -248,7 +275,17 @@ def week_view(
 
         persons_qs = (
             persons_qs.distinct()
-            .prefetch_related("personal_notes")
+            .prefetch_related(
+                Prefetch(
+                    "personal_notes",
+                    queryset=PersonalNote.objects.filter(
+                        week=wanted_week.week,
+                        year=wanted_week.year,
+                        lesson_period__in=lesson_periods_pk,
+                    ),
+                ),
+                "member_of__owners",
+            )
             .annotate(
                 absences_count=Count(
                     "personal_notes",
@@ -285,7 +322,7 @@ def week_view(
             )
         )
 
-        for extra_mark in ExtraMark.objects.all():
+        for extra_mark in extra_marks:
             persons_qs = persons_qs.annotate(
                 **{
                     extra_mark.count_label: Count(
@@ -304,24 +341,12 @@ def week_view(
         persons = []
         for person in persons_qs:
             persons.append(
-                {
-                    "person": person,
-                    "personal_notes": person.personal_notes.filter(
-                        week=wanted_week.week,
-                        year=wanted_week.year,
-                        lesson_period__in=lesson_periods_pk,
-                    ),
-                }
+                {"person": person, "personal_notes": list(person.personal_notes.all())}
             )
     else:
         persons = None
 
-    # Resort lesson periods manually because an union queryset doesn't support order_by
-    lesson_periods = sorted(
-        lesson_periods, key=lambda x: (x.period.weekday, x.period.period)
-    )
-
-    context["extra_marks"] = ExtraMark.objects.all()
+    context["extra_marks"] = extra_marks
     context["week"] = wanted_week
     context["weeks"] = get_weeks_for_year(year=wanted_week.year)
     context["lesson_periods"] = lesson_periods
@@ -369,7 +394,14 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
         LessonPeriod.objects.filter_group(group)
         .filter(lesson__validity__school_term=current_school_term)
         .distinct()
-        .prefetch_related("documentations", "personal_notes")
+        .prefetch_related(
+            "documentations",
+            "personal_notes",
+            "personal_notes__excuse_type",
+            "personal_notes__extra_marks",
+            "personal_notes__person",
+            "personal_notes__groups_of_person",
+        )
     )
 
     weeks = CalendarWeek.weeks_within(
@@ -404,35 +436,49 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
                     (lesson_period, documentations, notes, substitution)
                 )
 
-    persons = Person.objects.filter(
-        personal_notes__groups_of_person=group,
-        personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
-    ).annotate(
-        absences_count=Count(
-            "personal_notes__absent",
-            filter=Q(
-                personal_notes__absent=True,
-                personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+    persons = (
+        Person.objects.prefetch_related(
+            "personal_notes",
+            "personal_notes__excuse_type",
+            "personal_notes__extra_marks",
+            "personal_notes__lesson_period__lesson__subject",
+            "personal_notes__lesson_period__substitutions",
+            "personal_notes__lesson_period__substitutions__subject",
+            "personal_notes__lesson_period__substitutions__teachers",
+            "personal_notes__lesson_period__lesson__teachers",
+            "personal_notes__lesson_period__period",
+        )
+        .filter(
+            personal_notes__groups_of_person=group,
+            personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+        )
+        .annotate(
+            absences_count=Count(
+                "personal_notes__absent",
+                filter=Q(
+                    personal_notes__absent=True,
+                    personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+                ),
             ),
-        ),
-        excused=Count(
-            "personal_notes__absent",
-            filter=Q(
-                personal_notes__absent=True,
-                personal_notes__excused=True,
-                personal_notes__excuse_type__isnull=True,
-                personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+            excused=Count(
+                "personal_notes__absent",
+                filter=Q(
+                    personal_notes__absent=True,
+                    personal_notes__excused=True,
+                    personal_notes__excuse_type__isnull=True,
+                    personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+                ),
             ),
-        ),
-        unexcused=Count(
-            "personal_notes__absent",
-            filter=Q(
-                personal_notes__absent=True,
-                personal_notes__excused=False,
-                personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+            unexcused=Count(
+                "personal_notes__absent",
+                filter=Q(
+                    personal_notes__absent=True,
+                    personal_notes__excused=False,
+                    personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
+                ),
             ),
-        ),
-        tardiness=Sum("personal_notes__late"),
+            tardiness=Sum("personal_notes__late"),
+        )
     )
 
     for extra_mark in ExtraMark.objects.all():
@@ -471,7 +517,18 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     context["periods_by_day"] = periods_by_day
     context["lesson_periods"] = lesson_periods
     context["today"] = date.today()
-
+    context["lessons"] = (
+        group.lessons.all()
+        .select_related("validity", "subject")
+        .prefetch_related("teachers", "lesson_periods")
+    )
+    context["child_groups"] = group.child_groups.all().prefetch_related(
+        "lessons",
+        "lessons__validity",
+        "lessons__subject",
+        "lessons__teachers",
+        "lessons__lesson_periods",
+    )
     return render(request, "alsijil/print/full_register.html", context)
 
 
@@ -570,10 +627,16 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
 
                 person.refresh_from_db()
 
+    person_personal_notes = person.personal_notes.all().prefetch_related(
+        "lesson_period__lesson__groups",
+        "lesson_period__lesson__teachers",
+        "lesson_period__substitutions",
+    )
+
     if request.user.has_perm("alsijil.view_person_overview_personalnote", person):
-        allowed_personal_notes = person.personal_notes.all()
+        allowed_personal_notes = person_personal_notes.all()
     else:
-        allowed_personal_notes = person.personal_notes.filter(
+        allowed_personal_notes = person_personal_notes.filter(
             lesson_period__lesson__groups__owners=request.user.person
         )
 
@@ -591,6 +654,8 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
     context["personal_notes"] = personal_notes
     context["excuse_types"] = ExcuseType.objects.all()
 
+    extra_marks = ExtraMark.objects.all()
+    excuse_types = ExcuseType.objects.all()
     if request.user.has_perm("alsijil.view_person_statistics_personalnote", person):
         school_terms = SchoolTerm.objects.all().order_by("-date_start")
         stats = []
@@ -620,14 +685,14 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
             )
             stat.update(personal_notes.aggregate(tardiness=Sum("late")))
 
-            for extra_mark in ExtraMark.objects.all():
+            for extra_mark in extra_marks:
                 stat.update(
                     personal_notes.filter(extra_marks=extra_mark).aggregate(
                         **{extra_mark.count_label: Count("pk")}
                     )
                 )
 
-            for excuse_type in ExcuseType.objects.all():
+            for excuse_type in excuse_types:
                 stat.update(
                     personal_notes.filter(
                         absent=True, excuse_type=excuse_type
@@ -636,8 +701,10 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
 
             stats.append((school_term, stat))
         context["stats"] = stats
-    context["excuse_types"] = ExcuseType.objects.all()
-    context["extra_marks"] = ExtraMark.objects.all()
+
+    context["excuse_types"] = excuse_types
+    context["extra_marks"] = extra_marks
+
     return render(request, "alsijil/class_register/person.html", context)