Search code examples
djangodjango-filter

use django-filters on a queryset in the backend


Assuming I have a queryset and some filters I got from the front end, can I use the pre-defined FilterSet to filter over the queryset? example:

models.py

class User(models.Model):
    name = models.CharField(...)
    score = models.IntegerField(...)

filters.py

class UserFilter(django_filters.FilterSet):
    q = django_filters.CharFilter(method="text_search_filter")
    score_min = django_filters.NumberFilter(field_name="score", lookup_expr="gte")
    score_max = django_filters.NumberFilter(field_name="score", lookup_expr="lte")

    class Meta:
        model = User
        fields = {}

    def text_search_filter(self, queryset, name, value):
        return queryset.filter(name__icontains=value)

views.py

class UserView(View):
    filter_class = UserFilter
    ...
    def post(self, request, **kwargs):
        qs = User.object.all()
        filters = {"q": "john doe", "score_min": 5, "score_max": 10}

Can I call UserFilter and pass the filter dict? To prevent me applying those filters again, since I already have those defined in the UserFilter

Here's what I tried and didn't work:

views.py

    def post(self, request, **kwargs):
        qs = User.object.all()
        filters = {"q": "john doe", "score_min": 5, "score_max": 10}

        filter = UserFilter(request.GET, queryset=qs)
        filter.is_valid()
        qs = filter.filter_queryset(qs)  # Did not apply the filters


Solution

  • Here's what worked for me:

    the method filter_queryset uses form.cleaned_data as the filter paramaters. When I called it it was not initialised, therefor no filters were applied. I used the source code to create my own function that receives the filter params.

    def filter_queryset(filter_params, filterset, queryset):
        filters = filterset.filters
        for param, value in filter_params.items():
            ... # you might want to serialize some fields, like date (which is otherwise done under the hood to cleaned_data)
    
            queryset = filters[param].filter(queryset, value)
        return queryset.distinct()