1

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.

1
  • Why not subclass viewset.ListViewSet or viewset.ModelViewSet since you are using a model, then you don't need to provide list since it will be inherited. Commented Dec 18, 2017 at 15:40

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.