Skip to content

Commit

Permalink
✨ [#357] Support ordering and pagination params in request body
Browse files Browse the repository at this point in the history
Since the filters now can come through the request body, so can the ordering and the pagination params. So these need to be supported
  • Loading branch information
SilviaAmAm committed Feb 10, 2025
1 parent ba30cea commit bed01bc
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 8 deletions.
12 changes: 8 additions & 4 deletions backend/src/openarchiefbeheer/destruction/api/backends.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from django_filters.rest_framework import DjangoFilterBackend
from django_filters.utils import translate_validation
from rest_framework.filters import OrderingFilter

from openarchiefbeheer.utils.django_filters.backends import (
OrderingWithPostFilterBackend,
)


class NestedFilterBackend(DjangoFilterBackend):
Expand Down Expand Up @@ -38,7 +41,7 @@ def get_nested_filterset(self, request, view):
return nested_filterset_class(**kwargs)


class NestedOrderingFilterBackend(OrderingFilter):
class NestedOrderingFilterBackend(OrderingWithPostFilterBackend):
def get_valid_fields(self, queryset, view, context={}) -> list[tuple[str, str]]:
valid_fields = getattr(
view, context.get("ordering_fields_view_attr", "ordering_fields"), []
Expand Down Expand Up @@ -72,12 +75,13 @@ def is_term_valid(self, term, valid_fields) -> bool:
return term in valid_fields

def get_ordering(self, request, queryset, view) -> list[str]:
ordering_filters = self.get_ordering_filters(request)
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)
base_params = ordering_filters.get(base_ordering_param)
formatted_fields = []
if base_params:
fields = [param.strip() for param in base_params.split(",")]
Expand All @@ -88,7 +92,7 @@ def get_ordering(self, request, queryset, view) -> list[str]:
term for term in fields if self.is_term_valid(term, valid_fields)
]

nested_params = request.query_params.get(self.ordering_param)
nested_params = ordering_filters.get(self.ordering_param)
if nested_params:
fields = [param.strip() for param in nested_params.split(",")]
nested_queryset = view.nested_ordering_model.objects.all()
Expand Down
29 changes: 29 additions & 0 deletions backend/src/openarchiefbeheer/utils/django_filters/backends.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter


class NoModelFilterBackend(DjangoFilterBackend):
pass


class OrderingWithPostFilterBackend(OrderingFilter):
"""Support ordering params also in the request body."""

def get_ordering_filters(self, request):
return request.query_params or request.data

def get_ordering(self, request, queryset, view):
"""
Ordering is set by a comma delimited ?ordering=... query parameter.
The `ordering` query parameter can be overridden by setting
the `ordering_param` value on the OrderingFilter or by
specifying an `ORDERING_PARAM` value in the API settings.
"""
# Overriding where the filters are coming from (for us from the POST request body).
# Normally they are query params.
ordering_filters = self.get_ordering_filters(request)
params = ordering_filters.get(self.ordering_param)
if params:
fields = [param.strip() for param in params.split(",")]
ordering = self.remove_invalid_fields(queryset, fields, view, request)
if ordering:
return ordering

# No ordering was included, or all the ordering fields were invalid
return self.get_default_ordering(view)
14 changes: 14 additions & 0 deletions backend/src/openarchiefbeheer/utils/paginators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,17 @@
class PageNumberPagination(_PageNumberPagination):
page_size_query_param = "page_size"
page_size = 100


class PageNumberPaginationWithPost(_PageNumberPagination):
"""Support pagination param also in request body"""

page_size_query_param = "page_size"
page_size = 100

def get_page_number(self, request, paginator):
params = request.query_params or request.data
page_number = params.get(self.page_query_param) or 1
if page_number in self.last_page_strings:
page_number = paginator.num_pages
return page_number
10 changes: 6 additions & 4 deletions backend/src/openarchiefbeheer/zaken/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import mixins, viewsets
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated

from openarchiefbeheer.destruction.api.permissions import (
CanCoReviewPermission,
CanReviewPermission,
CanStartDestructionPermission,
)
from openarchiefbeheer.utils.paginators import PageNumberPagination
from openarchiefbeheer.utils.django_filters.backends import (
OrderingWithPostFilterBackend,
)
from openarchiefbeheer.utils.paginators import PageNumberPaginationWithPost

from ..models import Zaak
from .filtersets import ZaakFilterBackend, ZaakFilterSet
Expand Down Expand Up @@ -40,8 +42,8 @@ class ZakenViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
IsAuthenticated
& (CanStartDestructionPermission | CanReviewPermission | CanCoReviewPermission)
]
pagination_class = PageNumberPagination
filter_backends = (ZaakFilterBackend, OrderingFilter)
pagination_class = PageNumberPaginationWithPost
filter_backends = (ZaakFilterBackend, OrderingWithPostFilterBackend)
filterset_class = ZaakFilterSet
ordering_fields = "__all__"

Expand Down

0 comments on commit bed01bc

Please sign in to comment.