hburgund
hburgund

Reputation: 71

Django Rest Framework: Issue using OrderingFilter and django-filter simultaneously

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

Answers (1)

hburgund
hburgund

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

Related Questions