diff --git a/aleksis/apps/alsijil/managers.py b/aleksis/apps/alsijil/managers.py
index 681e3e562be5f8b26c4fd31fb543dcadbbe5fb29..6f097bc626f2de506423af20ba943445acb10c9d 100644
--- a/aleksis/apps/alsijil/managers.py
+++ b/aleksis/apps/alsijil/managers.py
@@ -8,13 +8,14 @@ from django.db.models.query_utils import Q
 
 from calendarweek import CalendarWeek
 
+from aleksis.apps.chronos.models import LessonEvent
 from aleksis.core.managers import (
     AlekSISBaseManagerWithoutMigrations,
     RecurrencePolymorphicManager,
 )
 
 if TYPE_CHECKING:
-    from aleksis.core.models import Group
+    from aleksis.core.models import Group, SchoolTerm
 
 
 class GroupRoleManager(AlekSISBaseManagerWithoutMigrations):
@@ -73,6 +74,31 @@ class GroupRoleAssignmentQuerySet(QuerySet):
 class DocumentationManager(RecurrencePolymorphicManager):
     """Manager adding specific methods to documentations."""
 
+    def for_school_term(self, school_term: "SchoolTerm"):
+        return self.filter(
+            datetime_start__date__gte=school_term.date_start,
+            datetime_end__date__lte=school_term.date_end,
+        )
+
+    def all_for_group(self, group: "Group"):
+        return self.for_school_term(group.school_term).filter(
+            pk__in=self.filter(course__groups=group)
+            .values_list("pk", flat=True)
+            .union(self.filter(course__groups__parent_groups=group).values_list("pk", flat=True))
+            .union(
+                self.filter(
+                    amends__in=LessonEvent.objects.filter(LessonEvent.objects.for_group_q(group))
+                ).values_list("pk", flat=True)
+            )
+        )
+
+    def all_planned_for_group(self, group: "Group"):
+        return self.for_school_term(group.school_term).filter(
+            pk__in=self.filter(
+                amends__in=LessonEvent.objects.filter(LessonEvent.objects.for_group_q(group))
+            ).values_list("pk", flat=True)
+        )
+
 
 class ParticipationStatusManager(RecurrencePolymorphicManager):
     """Manager adding specific methods to participation statuses."""
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index e1a2bd0ef2a2c49d0bdf124b21a6f550d303176c..b3186f6103de2d0f6781d03d9562e468124e80f3 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -1,12 +1,6 @@
-from django.db.models import FilteredRelation, Q, QuerySet, Value
-from django.db.models.aggregates import Count, Sum
 from django.utils.translation import gettext as _
 
-from aleksis.apps.chronos.models import LessonEvent
-from aleksis.apps.kolego.models import AbsenceReason
-from aleksis.core.models import Group, Person, SchoolTerm
-
-from .models import Documentation, ExtraMark
+from aleksis.core.models import Group, Person
 
 # Dynamically add extra permissions to Group and Person models in core
 # Note: requires migrate afterwards
@@ -32,112 +26,3 @@ Group.add_permission(
 )
 Group.add_permission("assign_grouprole", _("Can assign a group role for this group"))
 Person.add_permission("register_absence_person", _("Can register an absence for a person"))
-
-
-def annotate_person_statistics(
-    persons: QuerySet[Person],
-    participations_filter: Q,
-    personal_notes_filter: Q,
-    *,
-    ignore_filters: bool = False,
-) -> QuerySet[Person]:
-    """Annotate a queryset of persons with class register statistics."""
-
-    if ignore_filters:
-        persons = persons.annotate(
-            absence_count=Value(0),
-            filtered_participation_statuses=FilteredRelation(
-                "participations",
-                condition=Q(pk=None),
-            ),
-            filtered_personal_notes=FilteredRelation(
-                "new_personal_notes",
-                condition=Q(pk=None),
-            ),
-            participation_count=Value(0),
-            tardiness_count=Value(0),
-            tardiness_sum=Value(0),
-        )
-    else:
-        persons = persons.annotate(
-            filtered_participation_statuses=FilteredRelation(
-                "participations",
-                condition=(participations_filter),
-            ),
-            filtered_personal_notes=FilteredRelation(
-                "new_personal_notes",
-                condition=(personal_notes_filter),
-            ),
-        ).annotate(
-            participation_count=Count(
-                "filtered_participation_statuses",
-                filter=Q(filtered_participation_statuses__absence_reason__isnull=True),
-                distinct=True,
-            ),
-            absence_count=Count(
-                "filtered_participation_statuses",
-                filter=Q(filtered_participation_statuses__absence_reason__count_as_absent=True),
-                distinct=True,
-            ),
-            tardiness_sum=Sum("filtered_participation_statuses__tardiness", distinct=True),
-            tardiness_count=Count(
-                "filtered_participation_statuses",
-                filter=Q(filtered_participation_statuses__tardiness__gt=0),
-                distinct=True,
-            ),
-        )
-
-    persons = persons.order_by("last_name", "first_name")
-
-    for absence_reason in AbsenceReason.objects.all():
-        persons = persons.annotate(
-            **{
-                absence_reason.count_label: Count(
-                    "filtered_participation_statuses",
-                    filter=Q(
-                        filtered_participation_statuses__absence_reason=absence_reason,
-                    ),
-                    distinct=True,
-                )
-            }
-        )
-
-    for extra_mark in ExtraMark.objects.all():
-        persons = persons.annotate(
-            **{
-                extra_mark.count_label: Count(
-                    "filtered_personal_notes",
-                    filter=Q(filtered_personal_notes__extra_mark=extra_mark),
-                    distinct=True,
-                )
-            }
-        )
-
-    return persons
-
-
-def annotate_person_statistics_from_documentations(
-    persons: QuerySet[Person], docs: QuerySet[Documentation]
-) -> QuerySet[Person]:
-    """Annotate a queryset of persons with class register statistics from documentations."""
-    docs = list(docs.values_list("pk", flat=True))
-    return annotate_person_statistics(
-        persons,
-        Q(participations__related_documentation__in=docs),
-        Q(new_personal_notes__documentation__in=docs),
-        ignore_filters=len(docs) == 0,
-    )
-
-
-def annotate_person_statistics_for_school_term(
-    persons: QuerySet[Person], school_term: SchoolTerm, group: Group | None = None
-) -> QuerySet[Person]:
-    """Annotate a queryset of persons with class register statistics for a school term."""
-    documentations = Documentation.objects.filter(
-        datetime_start__date__gte=school_term.date_start,
-        datetime_end__date__lte=school_term.date_end,
-    )
-    if group:
-        lesson_events = LessonEvent.objects.filter(LessonEvent.objects.for_group_q(group))
-        documentations = documentations.filter(amends__in=lesson_events)
-    return annotate_person_statistics_from_documentations(persons, documentations)
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index f337be4f836c8f73383e952c88f79e229613e02a..975b8930e3e184aba8523795a2d86d3b77cd468e 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -21,8 +21,8 @@ from aleksis.core.util.core_helpers import (
     has_person,
 )
 
-from ..model_extensions import annotate_person_statistics_for_school_term
 from ..models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
+from ..util.statistics import StatisticsBuilder
 from .absences import (
     AbsencesForPersonsClearMutation,
     AbsencesForPersonsCreateMutation,
@@ -295,10 +295,14 @@ 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)
+        statistics = (
+            StatisticsBuilder(Person.objects.filter(id=person.id))
+            .use_from_school_term(school_term)
+            .annotate_statistics()
+            .build()
+        )
         return graphene_django_optimizer.query(
-            annotate_person_statistics_for_school_term(
-                Person.objects.filter(id=person.id), school_term
-            ).first(),
+            statistics.first(),
             info,
         )
 
@@ -343,9 +347,13 @@ class Query(graphene.ObjectType):
         school_term = get_active_school_term(info.context)
 
         members = group.members.all()
-        return graphene_django_optimizer.query(
-            annotate_person_statistics_for_school_term(members, school_term, group=group), info
+        statistics = (
+            StatisticsBuilder(members)
+            .use_from_group(group, school_term=school_term)
+            .annotate_statistics()
+            .build()
         )
+        return graphene_django_optimizer.query(statistics, info)
 
 
 class Mutation(graphene.ObjectType):
diff --git a/aleksis/apps/alsijil/tasks.py b/aleksis/apps/alsijil/tasks.py
index 71de0d315e6a2d7fbb66b99d5298d21b52502429..355396dcb91fdb1436df8ec0b62d78dadde87066 100644
--- a/aleksis/apps/alsijil/tasks.py
+++ b/aleksis/apps/alsijil/tasks.py
@@ -7,15 +7,14 @@ from django.utils.translation import gettext as _
 from celery.result import allow_join_result
 from celery.states import SUCCESS
 
-from aleksis.apps.chronos.models import LessonEvent
 from aleksis.apps.cursus.models import Course
 from aleksis.apps.kolego.models.absence import AbsenceReason
 from aleksis.core.models import Group, PDFFile
 from aleksis.core.util.celery_progress import ProgressRecorder, recorded_task
 from aleksis.core.util.pdf import generate_pdf_from_template
 
-from .model_extensions import annotate_person_statistics_from_documentations
 from .models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
+from .util.statistics import StatisticsBuilder
 
 
 @recorded_task
@@ -32,33 +31,6 @@ def generate_full_register_printout(
 ):
     """Generate a configurable register printout as PDF for a group."""
 
-    def prefetch_notable_participations(select_related=None, prefetch_related=None):
-        if not select_related:
-            select_related = []
-        if not prefetch_related:
-            prefetch_related = []
-        return Prefetch(
-            "participations",
-            to_attr="notable_participations",
-            queryset=ParticipationStatus.objects.filter(
-                Q(absence_reason__tags__short_name="class_register") | Q(tardiness__isnull=False)
-            )
-            .select_related("absence_reason", *select_related)
-            .prefetch_related(*prefetch_related),
-        )
-
-    def prefetch_personal_notes(name, select_related=None, prefetch_related=None):
-        if not select_related:
-            select_related = []
-        if not prefetch_related:
-            prefetch_related = []
-        return Prefetch(
-            name,
-            queryset=NewPersonalNote.objects.filter(Q(note__gt="") | Q(extra_mark__isnull=False))
-            .select_related("extra_mark", *select_related)
-            .prefetch_related(*prefetch_related),
-        )
-
     context = {}
 
     context["include_cover"] = include_cover
@@ -107,52 +79,44 @@ def generate_full_register_printout(
             2 + i, _number_of_steps, _(f"Loading group {group.short_name or group.name} ...")
         )
 
-        if include_members_table or include_person_overviews or include_coursebook:
-            documentations = Documentation.objects.filter(
-                Q(datetime_start__date__gte=group.school_term.date_start)
-                & Q(datetime_end__date__lte=group.school_term.date_end)
-                & Q(
-                    pk__in=Documentation.objects.filter(course__groups=group)
-                    .values_list("pk", flat=True)
-                    .union(
-                        Documentation.objects.filter(
-                            course__groups__parent_groups=group
-                        ).values_list("pk", flat=True)
-                    )
-                    .union(
-                        Documentation.objects.filter(
-                            amends__in=LessonEvent.objects.filter(
-                                LessonEvent.objects.for_group_q(group)
-                            )
-                        ).values_list("pk", flat=True)
-                    )
-                )
-            )
-
         if include_members_table or include_person_overviews:
-            group.members_with_stats = annotate_person_statistics_from_documentations(
-                group.members.all(), documentations
+            doc_query_set = Documentation.objects.select_related("subject").prefetch_related(
+                "teachers"
             )
 
-        if include_person_overviews:
-            doc_query_set = documentations.select_related("subject").prefetch_related("teachers")
-            group.members_with_stats = group.members_with_stats.prefetch_related(
-                prefetch_notable_participations(
-                    prefetch_related=[Prefetch("related_documentation", queryset=doc_query_set)]
-                ),
-                prefetch_personal_notes(
-                    "new_personal_notes",
-                    prefetch_related=[Prefetch("documentation", queryset=doc_query_set)],
-                ),
+            members_with_statistics = (
+                StatisticsBuilder(group.members.all()).use_from_group(group).annotate_statistics()
             )
+            if include_person_overviews:
+                members_with_statistics = members_with_statistics.prefetch_relevant_participations(
+                    documentation_with_details=doc_query_set
+                ).prefetch_relevant_personal_notes(documentation_with_details=doc_query_set)
+            members_with_statistics = members_with_statistics.build()
+            group.members_with_stats = members_with_statistics
 
         if include_teachers_and_subjects_table:
             group.as_list = [group]
 
         if include_coursebook:
-            group.documentations = documentations.order_by("datetime_start").prefetch_related(
-                prefetch_notable_participations(select_related=["person"]),
-                prefetch_personal_notes("personal_notes", select_related=["person"]),
+            group.documentations = (
+                Documentation.objects.all_for_group(group)
+                .order_by("datetime_start")
+                .prefetch_related(
+                    Prefetch(
+                        "participations",
+                        to_attr="relevant_participations",
+                        queryset=ParticipationStatus.objects.filter(
+                            Q(absence_reason__isnull=False) | Q(tardiness__isnull=False)
+                        ).select_related("absence_reason", "person"),
+                    ),
+                    Prefetch(
+                        "personal_notes",
+                        to_attr="relevant_personal_notes",
+                        queryset=NewPersonalNote.objects.filter(
+                            Q(note__gt="") | Q(extra_mark__isnull=False)
+                        ).select_related("extra_mark", "person"),
+                    ),
+                )
             )
 
     context["groups"] = groups
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html b/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html
index 6c91c34730b10116e190b4892bb26415a4ceed20..f8cd4eaddfe981f022e39dd466899b5f7fe733de 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html
@@ -94,7 +94,7 @@
   </thead>
 
   <tbody>
-  {% for participation in person.notable_participations %}
+  {% for participation in person.relevant_participations %}
     <tr>
       <td>{{ participation.related_documentation.datetime_start }}</td>
       <td>
@@ -122,7 +122,7 @@
   </thead>
 
   <tbody>
-  {% for note in person.new_personal_notes.all %}
+  {% for note in person.relevant_personal_notes.all %}
     <tr>
       <td>{{ note.documentation.datetime_start }}</td>
       <td>
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html b/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html
index ab626b7dd389ae6fa77732f5dd34328b31f3946a..95fb8e8f3977623346aa637d6f4986a1e85029bc 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html
@@ -53,7 +53,7 @@
         <td class="lesson-homework">{{ doc.homework }}</td>
         <td class="lesson-notes">
           {{ documentation.group_note }}
-          {% for participation in doc.notable_participations %}
+          {% for participation in doc.relevant_participations %}
             {% if participation.absence_reason %}
               <span class="lesson-note-absent">
                 {{ participation.person.full_name }}
@@ -69,7 +69,7 @@
               </span>
             {% endif %}
           {% endfor %}
-          {% for personal_note in doc.personal_notes.all %}
+          {% for personal_note in doc.relevant_personal_notes.all %}
             {% if personal_note.extra_mark %}
                 <span>
                 {{ personal_note.person.full_name }}
diff --git a/aleksis/apps/alsijil/util/statistics.py b/aleksis/apps/alsijil/util/statistics.py
new file mode 100644
index 0000000000000000000000000000000000000000..ee7cb3057dcf6cb564e8449dfb70adf50dcf1cd2
--- /dev/null
+++ b/aleksis/apps/alsijil/util/statistics.py
@@ -0,0 +1,260 @@
+from django.db.models import FilteredRelation, Prefetch, Q, QuerySet, Value
+from django.db.models.aggregates import Count, Sum
+
+from aleksis.apps.chronos.models import LessonEvent
+from aleksis.apps.kolego.models import AbsenceReason
+from aleksis.core.models import Group, Person, SchoolTerm
+
+from ..models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
+
+
+class BuilderError(Exception):
+    pass
+
+
+class StatisticsBuilder:
+    def __init__(self, persons: QuerySet[Person]) -> None:
+        self.qs: QuerySet[Person] = persons
+        self.participations_filter: Q | None = None
+        self.personal_notes_filter: Q | None = None
+        self.empty: bool = False
+        self._order()
+
+    def _order(self) -> "StatisticsBuilder":
+        """Order by last and first names."""
+        self.qs = self.qs.order_by("last_name", "first_name")
+        return self
+
+    def use_participations(
+        self,
+        participations_filter: Q,
+    ) -> "StatisticsBuilder":
+        """Set a filter for participations."""
+        self.participations_filter = participations_filter
+        return self
+
+    def use_personal_notes(
+        self,
+        personal_notes_filter: Q,
+    ) -> "StatisticsBuilder":
+        """Set a filter for personal notes."""
+        self.personal_notes_filter = personal_notes_filter
+        return self
+
+    def use_from_documentations(
+        self, documentations: QuerySet[Documentation]
+    ) -> "StatisticsBuilder":
+        """Set a filter for participations and personal notes from documentations."""
+        docs = list(documentations.values_list("pk", flat=True))
+        if len(docs) == 0:
+            self.empty = True
+        self.use_participations(Q(participations__related_documentation__in=docs))
+        self.use_personal_notes(Q(new_personal_notes__documentation__in=docs))
+        return self
+
+    def use_from_school_term(self, school_term: SchoolTerm) -> "StatisticsBuilder":
+        """Set a filter for participations and personal notes from school term."""
+        documentations = Documentation.objects.for_school_term(school_term)
+        self.use_from_documentations(documentations)
+        return self
+
+    def use_from_group(
+        self, group: Group, school_term: SchoolTerm | None = None
+    ) -> "StatisticsBuilder":
+        """Set a filter for participations and personal notes from group."""
+        school_term = school_term or group.school_term
+        if not school_term:
+            documentations = Documentation.objects.none()
+        else:
+            lesson_events = LessonEvent.objects.filter(LessonEvent.objects.for_group_q(group))
+            documentations = Documentation.objects.for_school_term(school_term).filter(
+                amends__in=lesson_events
+            )
+        self.use_from_documentations(documentations)
+        return self
+
+    def _annotate_filtered_participations(self, condition: Q | None = None) -> "StatisticsBuilder":
+        """Annotate a filtered relation for participations."""
+        if not self.participations_filter and not condition:
+            raise BuilderError
+        self.qs = self.qs.annotate(
+            filtered_participation_statuses=FilteredRelation(
+                "participations",
+                condition=condition or self.participations_filter,
+            )
+        )
+        return self
+
+    def _annotate_filtered_personal_notes(self, condition: Q | None = None) -> "StatisticsBuilder":
+        """Annotate a filtered relation for personal notes."""
+        if not self.personal_notes_filter and not condition:
+            raise BuilderError
+        self.qs = self.qs.annotate(
+            filtered_personal_notes=FilteredRelation(
+                "new_personal_notes",
+                condition=condition or self.personal_notes_filter,
+            ),
+        )
+        return self
+
+    def annotate_participation_statistics(self) -> "StatisticsBuilder":
+        """Annotate statistics for participations."""
+        if self.empty:
+            self.annotate_empty_participation_statistics()
+            return self
+        self._annotate_filtered_participations()
+
+        self.qs = self.qs.annotate(
+            participation_count=Count(
+                "filtered_participation_statuses",
+                filter=Q(filtered_participation_statuses__absence_reason__isnull=True),
+                distinct=True,
+            ),
+            absence_count=Count(
+                "filtered_participation_statuses",
+                filter=Q(filtered_participation_statuses__absence_reason__count_as_absent=True),
+                distinct=True,
+            ),
+            tardiness_sum=Sum("filtered_participation_statuses__tardiness", distinct=True),
+            tardiness_count=Count(
+                "filtered_participation_statuses",
+                filter=Q(filtered_participation_statuses__tardiness__gt=0),
+                distinct=True,
+            ),
+        )
+
+        for absence_reason in AbsenceReason.objects.all():
+            self.qs = self.qs.annotate(
+                **{
+                    absence_reason.count_label: Count(
+                        "filtered_participation_statuses",
+                        filter=Q(
+                            filtered_participation_statuses__absence_reason=absence_reason,
+                        ),
+                        distinct=True,
+                    )
+                }
+            )
+
+        return self
+
+    def annotate_personal_note_statistics(self) -> "StatisticsBuilder":
+        """Annotate statistics for personal notes."""
+        if self.empty:
+            self.annotate_empty_personal_note_statistics()
+            return self
+        self._annotate_filtered_personal_notes()
+
+        for extra_mark in ExtraMark.objects.all():
+            self.qs = self.qs.annotate(
+                **{
+                    extra_mark.count_label: Count(
+                        "filtered_personal_notes",
+                        filter=Q(filtered_personal_notes__extra_mark=extra_mark),
+                        distinct=True,
+                    )
+                }
+            )
+
+        return self
+
+    def annotate_statistics(self) -> "StatisticsBuilder":
+        """Annotate statistics for participations and personal notes."""
+        self.annotate_participation_statistics()
+        self.annotate_personal_note_statistics()
+
+        return self
+
+    def annotate_empty_participation_statistics(self) -> "StatisticsBuilder":
+        """Annotate with empty participation statistics."""
+        self.qs = self.qs.annotate(
+            absence_count=Value(0),
+            participation_count=Value(0),
+            tardiness_count=Value(0),
+            tardiness_sum=Value(0),
+        )
+        for absence_reason in AbsenceReason.objects.all():
+            self.qs = self.qs.annotate(**{absence_reason.count_label: Value(0)})
+
+        return self
+
+    def annotate_empty_personal_note_statistics(self) -> "StatisticsBuilder":
+        """Annotate with empty personal note statistics."""
+        for extra_mark in ExtraMark.objects.all():
+            self.qs = self.qs.annotate(**{extra_mark.count_label: Value(0)})
+
+        return self
+
+    def annotate_empty_statistics(self) -> "StatisticsBuilder":
+        """Annotate with empty statistics."""
+        self.annotate_empty_participation_statistics()
+        self.annotate_empty_personal_note_statistics()
+
+        return self
+
+    def prefetch_relevant_participations(
+        self,
+        select_related: list | None = None,
+        prefetch_related: list | None = None,
+        documentation_with_details: QuerySet | None = None,
+    ) -> "StatisticsBuilder":
+        """Prefetch relevant participations."""
+        if not select_related:
+            select_related = []
+        if not prefetch_related:
+            prefetch_related = []
+
+        if documentation_with_details:
+            prefetch_related.append(
+                Prefetch("related_documentation", queryset=documentation_with_details)
+            )
+        else:
+            select_related.append("related_documentation")
+        self.qs = self.qs.prefetch_related(
+            Prefetch(
+                "participations",
+                to_attr="relevant_participations",
+                queryset=ParticipationStatus.objects.filter(
+                    Q(absence_reason__isnull=False) | Q(tardiness__isnull=False)
+                )
+                .select_related("absence_reason", *select_related)
+                .prefetch_related(*prefetch_related),
+            )
+        )
+
+        return self
+
+    def prefetch_relevant_personal_notes(
+        self,
+        select_related: list | None = None,
+        prefetch_related: list | None = None,
+        documentation_with_details: QuerySet | None = None,
+    ) -> "StatisticsBuilder":
+        """Prefetch relevant personal notes."""
+        if not select_related:
+            select_related = []
+        if not prefetch_related:
+            prefetch_related = []
+
+        if documentation_with_details:
+            prefetch_related.append(Prefetch("documentation", queryset=documentation_with_details))
+        else:
+            select_related.append("documentation")
+
+        self.qs = self.qs.prefetch_related(
+            Prefetch(
+                "new_personal_notes",
+                to_attr="relevant_personal_notes",
+                queryset=NewPersonalNote.objects.filter(
+                    Q(note__gt="") | Q(extra_mark__isnull=False)
+                )
+                .select_related("extra_mark", *select_related)
+                .prefetch_related(*prefetch_related),
+            )
+        )
+
+        return self
+
+    def build(self) -> QuerySet[Person]:
+        """Build annotated queryset with statistics."""
+        return self.qs