Skip to content

Commit

Permalink
✨ [#667] Add nested ordering filter backend
Browse files Browse the repository at this point in the history
  • Loading branch information
SilviaAmAm committed Feb 4, 2025
1 parent 718a53c commit 611d3d4
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
75 changes: 75 additions & 0 deletions backend/src/openarchiefbeheer/destruction/api/backends.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django_filters.rest_framework import DjangoFilterBackend
from django_filters.utils import translate_validation
from rest_framework.filters import OrderingFilter


class NestedFilterBackend(DjangoFilterBackend):
Expand Down Expand Up @@ -35,3 +36,77 @@ def get_nested_filterset(self, request, view):
"request": request,
}
return nested_filterset_class(**kwargs)


class NestedOrderingFilterBackend(OrderingFilter):
def get_valid_fields(self, queryset, view, context={}) -> list[tuple[str, str]]:
valid_fields = getattr(
view, context.get("ordering_fields_view_attr", "ordering_fields"), []
)

if valid_fields is None:
# Default to allowing filtering on serializer fields
return self.get_default_valid_fields(queryset, view, {})

elif valid_fields == "__all__":
# View explicitly allows filtering on any model field
valid_fields = [
(field.name, field.verbose_name)
for field in queryset.model._meta.fields
]
valid_fields += [
(key, key.title().split("__")) for key in queryset.query.annotations
]
else:
valid_fields = [
(item, item) if isinstance(item, str) else item for item in valid_fields
]
return valid_fields

def get_valid_fields_keys(self, valid_fields) -> list[str]:
return [item[0] for item in valid_fields]

def is_term_valid(self, term, valid_fields) -> bool:
if term.startswith("-"):
term = term[1:]
return term in valid_fields

def get_ordering(self, request, queryset, view) -> list[str]:
base_ordering_param = (
f"{view.nested_ordering_prefix}-{self.ordering_param}"
if view.nested_ordering_prefix
else self.ordering_param
)
base_params = request.query_params.get(base_ordering_param)
formatted_fields = []
if base_params:
fields = [param.strip() for param in base_params.split(",")]
valid_fields = self.get_valid_fields_keys(
self.get_valid_fields(queryset, view)
)
formatted_fields = [
term for term in fields if self.is_term_valid(term, valid_fields)
]

nested_params = request.query_params.get(self.ordering_param)
if nested_params:
fields = [param.strip() for param in nested_params.split(",")]
nested_queryset = view.nested_ordering_model.objects.all()
valid_fields = self.get_valid_fields_keys(
self.get_valid_fields(
nested_queryset,
view,
context={"ordering_fields_view_attr": "nested_ordering_fields"},
)
)

for term in fields:
if not self.is_term_valid(term, valid_fields):
continue

if is_reverse := term.startswith("-"):
term = term[1:]
formatted_fields.append(
f"{"-" if is_reverse else ""}{view.nested_ordering_relation_field}__{term}"
)
return formatted_fields
17 changes: 14 additions & 3 deletions backend/src/openarchiefbeheer/destruction/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from openarchiefbeheer.logging import logevent
from openarchiefbeheer.utils.paginators import PageNumberPagination
from openarchiefbeheer.zaken.api.filtersets import ZaakFilterSet
from openarchiefbeheer.zaken.models import Zaak

from ..constants import DestructionListItemAction, InternalStatus, ListRole, ListStatus
from ..models import (
Expand All @@ -36,7 +37,7 @@
)
from ..tasks import delete_destruction_list
from ..utils import process_new_reviewer
from .backends import NestedFilterBackend
from .backends import NestedFilterBackend, NestedOrderingFilterBackend
from .filtersets import (
DestructionListCoReviewFilterset,
DestructionListFilterset,
Expand Down Expand Up @@ -465,12 +466,17 @@ class DestructionListItemsViewSet(
viewsets.GenericViewSet,
):
serializer_class = DestructionListItemReadSerializer
filter_backends = (NestedFilterBackend,)
filter_backends = (NestedFilterBackend, NestedOrderingFilterBackend)
filterset_class = DestructionListItemFilterset
filterset_kwargs = {"prefix": "item"}
nested_filterset_class = ZaakFilterSet
nested_filterset_relation_field = "zaak"
pagination_class = PageNumberPagination
ordering_fields = "__all__"
nested_ordering_fields = "__all__"
nested_ordering_model = Zaak
nested_ordering_relation_field = "zaak"
nested_ordering_prefix = "item"

def get_queryset(self):
review_response_items = ReviewItemResponse.objects.filter(
Expand Down Expand Up @@ -593,10 +599,15 @@ class DestructionListItemReviewViewSet(mixins.ListModelMixin, viewsets.GenericVi
"destruction_list_item__zaak"
)
filterset_class = DestructionListReviewItemFilterset
filter_backends = (NestedFilterBackend,)
filter_backends = (NestedFilterBackend, NestedOrderingFilterBackend)
filterset_kwargs = {"prefix": "item-review"}
nested_filterset_class = ZaakFilterSet
nested_filterset_relation_field = "destruction_list_item__zaak"
ordering_fields = "__all__"
nested_ordering_fields = "__all__"
nested_ordering_model = Zaak
nested_ordering_relation_field = "destruction_list_item__zaak"
nested_ordering_prefix = "item-review"


@extend_schema_view(
Expand Down

0 comments on commit 611d3d4

Please sign in to comment.