Use get_serializer_class in ordering filter

OrderingFilter backend checks whether a view specifies an
ordering fields or serializer_class attribute. Views can however
override get_serializer_class to determine the serializer_class
but the OrderingFilter doesn't catch this. This patch fixes that.
This commit is contained in:
kmwenja 2015-10-09 11:22:59 +03:00 committed by Kennedy Mwenja
parent 35ace2e9ec
commit 4bcc8cda89
2 changed files with 28 additions and 3 deletions

View File

@ -228,9 +228,12 @@ class OrderingFilter(BaseFilterBackend):
if valid_fields is None:
# Default to allowing filtering on serializer fields
serializer_class = getattr(view, 'serializer_class')
if serializer_class is None:
serializer_class = view.get_serializer_class()
if serializer_class is None:
msg = ("Cannot use %s on a view which does not have either a "
"'serializer_class' or 'ordering_fields' attribute.")
"'serializer_class', an overriding 'get_serializer_class' "
"or 'ordering_fields' attribute.")
raise ImproperlyConfigured(msg % self.__class__.__name__)
valid_fields = [
(field.source or field_name, field.label)

View File

@ -754,6 +754,28 @@ class OrderingFilterTests(TestCase):
self.assertContains(response, 'verbose title')
def test_ordering_with_overridden_get_serializer_class(self):
class OrderingListView(generics.ListAPIView):
queryset = OrderingFilterModel.objects.all()
filter_backends = (filters.OrderingFilter,)
ordering = ('title',)
# note: no ordering_fields and serializer_class speficied
def get_serializer_class(self):
return OrderingFilterSerializer
view = OrderingListView.as_view()
request = factory.get('/', {'ordering': 'text'})
response = view(request)
self.assertEqual(
response.data,
[
{'id': 1, 'title': 'zyx', 'text': 'abc'},
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
{'id': 3, 'title': 'xwv', 'text': 'cde'},
]
)
class SensitiveOrderingFilterModel(models.Model):
username = models.CharField(max_length=20)