Search code examples
pythondjangodjango-rest-frameworkdjango-filter

django-filters: icontains type of lookup expression doesn't work properly


I am using django-filter to filter the result query based on the user input.

Imagine that I have the following Post:

[
    {
        "id": 1,
        "title": "salam",
        "content": "chetori",
        "is_draft": false,
        "author": 1
    }
]

I have created a filterset_class as following:

class PostFilter(filter.FilterSet):
    class Meta:
        model = Post
        fields = {
            'title': ['icontains'],
            'content': ['icontains'],
        }

whenever I use that icontains doesn't work properly, for example http://localhost:8000/posts/?content=chetorz query should returns empty list but it doesn't:

query result

But it works whenever I add the following line to project settings.py:

FILTERS_DEFAULT_LOOKUP_EXPR = 'icontains'

I don't know how can I change the code to work properly without changing the default behavior of the LOOKUP_EXPR.

PS views.py:

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    filter_backends = [rest_filters.SearchFilter, filters.DjangoFilterBackend]
    filterset_class = PostFilter
    search_fields = ['title', 'content', 'author__user__username']

    def get_permissions(self):
        if self.action == "create":
            self.permission_classes = [permissions.IsAuthenticated]

        elif self.action == "list":
            pass

        return super(PostViewSet, self).get_permissions()


Solution

  • For your filterset, you need to append the lookup, so:

    http://localhost:8000/posts/?content__icontains=chetorz

    You can however work by default with an icontains lookup, by specifying the field manually, like:

    class PostFilter(filter.FilterSet):
        title = django_filters.CharFilter(lookup_expr='icontains')
        content = django_filters.CharFilter(lookup_expr='icontains')
    
        class Meta:
            model = Post
            fields = ['title', 'content']