From 7e71d534e0e8955fc7beab73dfa25a4dd985686e Mon Sep 17 00:00:00 2001 From: Scott Gigante Date: Sat, 9 Dec 2023 13:59:41 -0500 Subject: [PATCH] adds `get_ordering` method to GenericAPIView following the pattern of e.g. `django.contrib.admin.ModelAdmin.get_fieldsets`, this PR adds an overrideable accessor to get `viewset.ordering` in order to enable dynamic default orderings. An example of where this is useful is in the case of a SearchFilter which returns results ranked based on similarity, in which case the default ordering should be ignored/bypassed. --- rest_framework/filters.py | 6 +++--- rest_framework/generics.py | 9 +++++++++ tests/test_pagination.py | 13 +++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/rest_framework/filters.py b/rest_framework/filters.py index 065e72f94..05073c86e 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -242,10 +242,10 @@ class OrderingFilter(BaseFilterBackend): return ordering # No ordering was included, or all the ordering fields were invalid - return self.get_default_ordering(view) + return self.get_default_ordering(request, queryset, view) - def get_default_ordering(self, view): - ordering = getattr(view, 'ordering', None) + def get_default_ordering(self, request, queryset, view): + ordering = view.get_ordering(request, queryset) if isinstance(ordering, str): return (ordering,) return ordering diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 167303321..2290d3ce9 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -104,6 +104,15 @@ class GenericAPIView(views.APIView): return obj + def get_ordering(self, request, queryset): + """ + Returns the default ordering defined on the view. + + You may want to override this if you wish the default ordering to be dependent + on the request. + """ + return getattr(self, "ordering", None) + def get_serializer(self, *args, **kwargs): """ Return the serializer instance that should be used for validating and diff --git a/tests/test_pagination.py b/tests/test_pagination.py index 090eb0d81..c7105e64a 100644 --- a/tests/test_pagination.py +++ b/tests/test_pagination.py @@ -609,6 +609,13 @@ class TestLimitOffset: } +class GenericOrderedMockView: + filter_backends = (filters.OrderingFilter,) + + def get_ordering(self, *args, **kwargs): + return getattr(self, 'ordering', None) + + class CursorPaginationTestsMixin: def test_invalid_cursor(self): @@ -617,8 +624,7 @@ class CursorPaginationTestsMixin: self.pagination.paginate_queryset(self.queryset, request) def test_use_with_ordering_filter(self): - class MockView: - filter_backends = (filters.OrderingFilter,) + class MockView(GenericOrderedMockView): ordering_fields = ['username', 'created'] ordering = 'created' @@ -635,8 +641,7 @@ class CursorPaginationTestsMixin: assert ordering == ('created',) def test_use_with_ordering_filter_without_ordering_default_value(self): - class MockView: - filter_backends = (filters.OrderingFilter,) + class MockView(GenericOrderedMockView): ordering_fields = ['username', 'created'] request = Request(factory.get('/'))