Skip to content

Commit

Permalink
⚡ - perf: attempt to increase performance of DestructionList related …
Browse files Browse the repository at this point in the history
…API endpoints
  • Loading branch information
svenvandescheur committed Dec 12, 2024
1 parent d5df99f commit 1e92c7e
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 20 deletions.
53 changes: 44 additions & 9 deletions backend/src/openarchiefbeheer/accounts/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.contrib.auth.models import Permission
from django.db.models import Q
from django.utils.translation import gettext_lazy as _

from drf_spectacular.utils import extend_schema_field
Expand Down Expand Up @@ -34,15 +35,49 @@ class Meta:

@extend_schema_field(RoleSerializer)
def get_role(self, user: User) -> dict | None:
data = {}
for permission in Permission.objects.filter(user=user):
data[permission.codename] = True

for group in user.groups.all():
for permission in group.permissions.all():
data[permission.codename] = True
# Retrieve all permission codenames.
permissions = []

serializer = RoleSerializer(data=data)
serializer.is_valid()
try:
"""
Annotating a (User) queryset with:
return serializer.data
- `user_permission_codenames`
- `group_permission_codenames`
can improve performance by reducing the number of queries needed.
Example:
queryset.annotate(
user_permission_codenames=ArrayAgg(
"user_permissions__codename",
distinct=True,
),
group_permission_codenames=ArrayAgg(
"groups__permissions__codename",
distinct=True,
),
)
"""
permissions += user.user_permission_codenames
permissions += user.group_permission_codenames

except AttributeError:
permissions = (
Permission.objects.filter(Q(user=user) | Q(group__user=user))
.distinct()
.values_list("codename", flat=True)
)

permissions_set = set(permissions)

data = {
"can_start_destruction": "can_start_destruction" in permissions_set,
"can_review_destruction": "can_review_destruction" in permissions_set,
"can_co_review_destruction": "can_co_review_destruction" in permissions_set,
"can_review_final_list": "can_review_final_list" in permissions_set,
}

return RoleSerializer(data).data
57 changes: 46 additions & 11 deletions backend/src/openarchiefbeheer/destruction/api/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from datetime import date, timedelta

from django.contrib.auth.models import Group, Permission
from django.contrib.postgres.aggregates import ArrayAgg
from django.db import transaction
from django.db.models import Case, OuterRef, Prefetch, QuerySet, Subquery, Value, When
from django.shortcuts import get_object_or_404
Expand All @@ -17,6 +19,7 @@
from openarchiefbeheer.utils.paginators import PageNumberPagination
from openarchiefbeheer.zaken.api.filtersets import ZaakFilterSet

from ...accounts.models import User
from ..constants import (
WAITING_PERIOD,
DestructionListItemAction,
Expand Down Expand Up @@ -221,18 +224,50 @@ class DestructionListViewSet(
viewsets.GenericViewSet,
):
serializer_class = DestructionListWriteSerializer
queryset = (
DestructionList.objects.all()
.select_related("author", "assignee")
.prefetch_related(
Prefetch(
"assignees",
queryset=DestructionListAssignee.objects.prefetch_related(
"user__user_permissions"
).order_by("pk"),
)
)
user_prefetch = User.objects.prefetch_related(
Prefetch(
"user_permissions",
queryset=Permission.objects.select_related("content_type").order_by(
"codename"
),
),
Prefetch(
"groups",
queryset=Group.objects.prefetch_related(
Prefetch(
"permissions",
queryset=Permission.objects.select_related("content_type").order_by(
"codename"
),
)
),
),
).annotate(
user_permission_codenames=ArrayAgg("user_permissions__codename", distinct=True),
group_permission_codenames=ArrayAgg(
"groups__permissions__codename", distinct=True
),
)
queryset = DestructionList.objects.all().prefetch_related(
Prefetch(
"author",
queryset=user_prefetch,
),
Prefetch(
"assignee",
queryset=user_prefetch,
),
Prefetch(
"assignees",
queryset=DestructionListAssignee.objects.prefetch_related(
Prefetch(
"user",
queryset=user_prefetch,
)
).order_by("pk"),
),
)

lookup_field = "uuid"
filter_backends = (DjangoFilterBackend,)
filterset_class = DestructionListFilterset
Expand Down

0 comments on commit 1e92c7e

Please sign in to comment.