Search code examples
djangodjango-rest-frameworkdjango-filterdjango-filters

django-filters filter by Boolean field with DRF


I'm following this tutorial, specifically the django-filter-backend section.

I am unable to get this to work. My goal is to retrieve a list of "containers" that have the "in_use" field set to True, but it keeps returning all the records in the table. I can't see what I am missing. I have added django-filters to my installed apps list and also added this to my REST_FRAMEWORK block:

'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']

This is the API endpoint I'm trying to hit in postman:

http://127.0.0.1:8000/displaydata/containers?in_use=True``` I've tried passing both 'True' and 'true', as well as 0s and 1s.

views.py

class ContainerViews(APIView):
    def get(self, request, id=None):
        if id:
            container = Container.objects.get(id=id)
            serializer = ContainerSerializer(container)
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
        else:
            containers = Container.objects.all()
            serializer = ContainerSerializer(containers, many=True)
            filter_backends = [DjangoFilterBackend]
            filterset_fields = ['in_use']
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)

Solution

  • You need to pass queryset and filter_backends as class attributes like this

    class ProductList(generics.ListAPIView):
        queryset = Container.objects.all()
        serializer_class = ContainerSerializer
        filter_backends = [DjangoFilterBackend]
        filterset_fields = ['in_use']
    

    This View only serves 'list' requests (many models). If you want also serve 'get' requests (single model by ID) you need ReadOnlyModelViewSet

    class ProductViewSet(ReadOnlyModelViewSet):
        queryset = Container.objects.all()
        serializer_class = ContainerSerializer
        filter_backends = [DjangoFilterBackend]
        filterset_fields = ['in_use']
    

    You can use it in urls.py like this

    router = DefaultRouter()
    router.register("product", ProductViewSet)
    urlpatterns = [
        path("", include(router.urls)),
        ...
    ]