Reputation: 71
I have a viewset which needs to have both flexible ordering by parameter and filtering by parameter for a custom list()
over-ride. I am able to get ordering to work as well as filtering on various parameters via django-filter
, but I cannot get them both to function simultaneously.
Here is my simplified views.py
code that works for ordering the results:
class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):
queryset = Asset.objects.all()
pagination_class = AssetPagination
serializer_class = serializers.AssetSerializer
filter_backends = (OrderingFilter, )
ordering_fields = ('id', 'session_id')
filter_class = AssetFilterSet
def list(self, request):
assets = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(assets, many=True)
return Response(serializer.data)
And here is the code that works for filtering:
class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):
queryset = Asset.objects.all()
pagination_class = AssetPagination
serializer_class = serializers.AssetSerializer
filter_backends = (OrderingFilter, )
ordering_fields = ('id', 'session_id')
filter_class = AssetFilterSet
def list(self, request):
assets = AssetFilterSet(request.query_params)
serializer = self.get_serializer(assets, many=True)
return Response(serializer.data)
And finally, my filters.py
code:
class AssetFilterSet(django_filters.FilterSet):
project_id = django_filters.NumberFilter()
submitted = django_filters.TypedChoiceFilter(choices=BOOLEAN_CHOICES, coerce=strtobool)
class Meta:
model = Asset
fields = ['project',
'submitted']
The only difference is the first line in list()
. For some reason, it seems like the AssetFilterSet
needs to be applied directly within list()
in order to take effect and is otherwise bypassed if I use self.filter_queryset
in list()
despite being specified by filter_class = AssetFilterSet
.
Upvotes: 1
Views: 2563
Reputation: 71
I will answer my own question. Turns out it is a very simple fix; you must include BOTH DjangoFilterBackend
and OrderingFilter
as filter_backends
explicitly despite DjangoFilterBackend
being specified globally in SETTINGS.
Here's the working code:
class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):
queryset = Asset.objects.all()
pagination_class = AssetPagination
serializer_class = serializers.AssetSerializer
filter_backends = (DjangoFilterBackend, OrderingFilter,)
ordering_fields = ('id', 'session_id')
filter_class = AssetFilterSet
def list(self, request):
assets = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(assets, many=True)
return Response(serializer.data)
I was under the impression that specifying DjangoFilterBackend
in SETTINGS meant that it would be included by default and adding a filter_backends
filter would add to it, not replace it. Live and learn!
Upvotes: 2