diff --git a/aleksis/apps/alsijil/managers.py b/aleksis/apps/alsijil/managers.py index 4c7741d3b89620b1682532192acf7fb9ad1c0196..ab9daaa7ebb171b9979fa8893fc7eaa0c598a31d 100644 --- a/aleksis/apps/alsijil/managers.py +++ b/aleksis/apps/alsijil/managers.py @@ -89,6 +89,9 @@ class PersonalNoteManager(CurrentSiteManagerWithoutMigrations): "lesson_period__period", "lesson_period__lesson__validity", "lesson_period__lesson__validity__school_term", + "event", + "extra_lesson", + "extra_lesson__subject", ) .prefetch_related("extra_marks") ) diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html index 8c83accaf9b7cfc9e07a2b05c16961d3f959fd75..07d65508b31f8d6faad586a88f54bb8a30b78f3c 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html @@ -318,12 +318,7 @@ </span> {% for person in persons %} <h5 class="card-title"> - {% has_perm "alsijil.view_person_overview" user person.person as can_view_person_overview %} - {% if can_view_person_overview %} - <a href="{% url "overview_person" person.person.pk %}">{{ person.person.full_name }}</a> - {% else %} - {{ person.person.full_name }} - {% endif %} + <a href="{% url "overview_person" person.person.pk %}">{{ person.person.full_name }}</a> {% has_perm "alsijil.register_absence" user person.person as can_register_absence %} {% if can_register_absence %} <a class="btn primary-color waves-effect waves-light right" @@ -335,7 +330,7 @@ </h5> {% if group_roles %} <p> - {% for assignment in person.person.group_roles.all %} + {% for assignment in person.group_roles %} {% include "alsijil/group_role/chip.html" with role=assignment.role small=assignment.date_range %} {% endfor %} </p> @@ -356,17 +351,15 @@ </p> {% endfor %} {% for note in person.personal_notes %} - {% if note.remarks %} - <blockquote> - {{ note.remarks }} - {% weekday_to_date week note.register_object.period.weekday as note_date %} - <em class="right"> - <a href="{{ note.register_object.alsijil_url }}"> - {{ note.date }}, {{ note.register_object.get_subject.name }} - </a> - </em> - </blockquote> - {% endif %} + <blockquote> + {{ note.remarks }} + {% weekday_to_date week note.register_object.period.weekday as note_date %} + <em class="right"> + <a href="{{ note.register_object.alsijil_url }}"> + {{ note.date }}, {{ note.register_object.get_subject.name }} + </a> + </em> + </blockquote> {% endfor %} {% endfor %} </div> diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py index 628ae7ae5e0079fe402df9e44c84ef9c07a36877..1759a5446d204d61c87f5bd1cbe9e3e031d95be2 100644 --- a/aleksis/apps/alsijil/util/predicates.py +++ b/aleksis/apps/alsijil/util/predicates.py @@ -98,13 +98,20 @@ def is_person_group_owner(user: User, obj: Person) -> bool: the owner of any group of the given person. """ if obj: - for group in obj.member_of.all(): - if user.person in list(group.owners.all()): + for group in use_prefetched(obj, "member_of"): + if user.person in use_prefetched(group, "owners"): return True return False return False +def use_prefetched(obj, attr): + prefetched_attr = f"{attr}_prefetched" + if hasattr(obj, prefetched_attr): + return getattr(obj, prefetched_attr) + return getattr(obj, attr).all() + + @predicate def is_person_primary_group_owner(user: User, obj: Person) -> bool: """ @@ -114,7 +121,7 @@ def is_person_primary_group_owner(user: User, obj: Person) -> bool: the owner of the primary group of the given person. """ if obj.primary_group: - return user.person in obj.primary_group.owners.all() + return user.person in use_prefetched(obj.primary_group, "owners") return False @@ -127,7 +134,7 @@ def has_person_group_object_perm(perm: str): @predicate(name) def fn(user: User, obj: Person) -> bool: - groups = obj.member_of.all() + groups = use_prefetched(obj, "member_of") for group in groups: if check_object_permission(user, perm, group, checker_obj=obj): return True diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 77e593943e10d7100ba2cf3b90c804c5ae8d957c..76608cda46699bf8e2f99f3d8fcbb0f0af4e74eb 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -1,3 +1,4 @@ +import time from contextlib import nullcontext from copy import deepcopy from datetime import date, datetime, timedelta @@ -280,6 +281,16 @@ def register_object( return render(request, "alsijil/class_register/lesson.html", context) +class catchtime(object): + def __enter__(self): + self.t = time.time() + return self + + def __exit__(self, type_, value, traceback): + self.t = time.time() - self.t + print(self.t) + + @permission_required("alsijil.view_week", fn=get_timetable_instance_by_pk) def week_view( request: HttpRequest, @@ -373,6 +384,7 @@ def week_view( if show_group_roles: group_roles = GroupRole.objects.with_assignments(wanted_week, [group]) context["group_roles"] = group_roles + group_roles_persons = GroupRoleAssignment.objects.in_week(wanted_week).for_group(group) extra_marks = ExtraMark.objects.all() @@ -380,11 +392,16 @@ def week_view( lesson_periods_pk = list(lesson_periods.values_list("pk", flat=True)) lesson_periods = annotate_documentations(LessonPeriod, wanted_week, lesson_periods_pk) - events_pk = list(events.values_list("pk", flat=True)) + events_pk = [event.pk for event in events] events = annotate_documentations(Event, wanted_week, events_pk) extra_lessons_pk = list(extra_lessons.values_list("pk", flat=True)) extra_lessons = annotate_documentations(ExtraLesson, wanted_week, extra_lessons_pk) + groups = Group.objects.filter( + Q(lessons__lesson_periods__in=lesson_periods_pk) + | Q(events__in=events_pk) + | Q(extra_lessons__in=extra_lessons_pk) + ) else: lesson_periods_pk = [] events_pk = [] @@ -399,22 +416,39 @@ def week_view( elif group: persons_qs = persons_qs.filter(member_of=group) else: - persons_qs = persons_qs.filter( - Q(member_of__lessons__lesson_periods__in=lesson_periods_pk) - | Q(member_of__events__in=events_pk) - | Q(member_of__extra_lessons__in=extra_lessons_pk) - ) + persons_qs = persons_qs.filter(member_of__in=groups) # Prefetch object permissions for persons and groups the persons are members of # because the object permissions are checked for both persons and groups checker = ObjectPermissionChecker(request.user) - checker.prefetch_perms(persons_qs) - checker.prefetch_perms(Group.objects.filter(members__in=persons_qs)) - + with catchtime(): + print("Prefetch checker") + checker.prefetch_perms(persons_qs.prefetch_related(None)) + checker.prefetch_perms(groups) + + with catchtime(): + print("personal notes") + prefetched_personal_notes = list( + PersonalNote.objects.filter( # + Q(event__in=events_pk) + | Q( + week=wanted_week.week, + year=wanted_week.year, + lesson_period__in=lesson_periods_pk, + ) + | Q(extra_lesson__in=extra_lessons_pk) + ).filter(~Q(remarks="")) + ) persons_qs = ( - Person.objects.filter(pk__in=persons_qs) - .select_related("primary_group") - .prefetch_related("primary_group__owners") + persons_qs.select_related("primary_group") + .prefetch_related( + Prefetch( + "primary_group__owners", + queryset=Person.objects.filter(pk=request.user.person.pk), + to_attr="owners_prefetched", + ), + Prefetch("member_of", queryset=groups, to_attr="member_of_prefetched"), + ) .annotate( filtered_personal_notes=FilteredRelation( "personal_notes", @@ -429,31 +463,8 @@ def week_view( ), ) ) - .prefetch_related( - Prefetch( - "personal_notes", - queryset=PersonalNote.objects.filter( - Q(event__in=events_pk) - | Q( - week=wanted_week.week, - year=wanted_week.year, - lesson_period__in=lesson_periods_pk, - ) - | Q(extra_lesson__in=extra_lessons_pk) - ), - ), - "member_of__owners", - ) ) - # Annotate group roles - if show_group_roles: - persons_qs = persons_qs.prefetch_related( - Prefetch( - "group_roles", - queryset=GroupRoleAssignment.objects.in_week(wanted_week).for_group(group), - ), - ) persons_qs = persons_qs.annotate( absences_count=Count( "filtered_personal_notes", filter=Q(filtered_personal_notes__absent=True), @@ -481,14 +492,22 @@ def week_view( ) persons = [] + with catchtime(): + print("Persons") + persons_test = list(persons_qs) for person in persons_qs: personal_notes = [] - for note in person.personal_notes.all(): + for note in filter(lambda note: note.person_id == person.pk, prefetched_personal_notes): if note.lesson_period: note.lesson_period.annotate_week(wanted_week) personal_notes.append(note) person.set_object_permission_checker(checker) - persons.append({"person": person, "personal_notes": personal_notes}) + person_dict = {"person": person, "personal_notes": personal_notes} + if show_group_roles: + person_dict["group_roles"] = filter( + lambda role: role.person_id == person.pk, group_roles_persons + ) + persons.append(person_dict) else: persons = None @@ -508,23 +527,27 @@ def week_view( regrouped_objects = {} - for register_object in list(lesson_periods) + list(extra_lessons): - register_object.weekday = register_object.period.weekday - regrouped_objects.setdefault(register_object.period.weekday, []) - regrouped_objects[register_object.period.weekday].append(register_object) - - for event in events: - weekday_from = event.get_start_weekday(wanted_week) - weekday_to = event.get_end_weekday(wanted_week) - - for weekday in range(weekday_from, weekday_to + 1): - # Make a copy in order to keep the annotation only on this weekday - event_copy = deepcopy(event) - event_copy.annotate_day(wanted_week[weekday]) - event_copy.weekday = weekday - - regrouped_objects.setdefault(weekday, []) - regrouped_objects[weekday].append(event_copy) + with catchtime(): + print("Register objects") + for register_object in list(lesson_periods) + list(extra_lessons): + register_object.weekday = register_object.period.weekday + regrouped_objects.setdefault(register_object.period.weekday, []) + regrouped_objects[register_object.period.weekday].append(register_object) + + with catchtime(): + print("events") + for event in events: + weekday_from = event.get_start_weekday(wanted_week) + weekday_to = event.get_end_weekday(wanted_week) + + for weekday in range(weekday_from, weekday_to + 1): + # Make a copy in order to keep the annotation only on this weekday + event_copy = deepcopy(event) + event_copy.annotate_day(wanted_week[weekday]) + event_copy.weekday = weekday + + regrouped_objects.setdefault(weekday, []) + regrouped_objects[weekday].append(event_copy) # Sort register objects for weekday in regrouped_objects.keys():