NDZIE Patrick Joel
NDZIE Patrick Joel

Reputation: 1142

How to filter query with comma separated parameters in Django (DRF Filtering)

Please my question is not a duplicated, i have already search for it but with no consistent result. So i'm building a restfull api with djangorestframework

I want this query like

http://localhost:8000/api/products/?category_name_fr=shirt,shoes

to find all products where category_name_fr contains shirt or shoes

In order to do this after some googling i wrote a custom django filter class (MultiValueCharFilter) but the filter does not actually behave like i want. When i make a query like the above, it returns me all the product in ProductTable. But when i make a query like the bellow, the filtering is done properly

http://localhost:8000/api/products/?category_name_fr=shirt

Here is the source code of my filters.py file, the product class is ProductList

    from django_filters import rest_framework as filters
    from .models import  ProductList
    from django_filters import Filter
    from django_filters.fields import Lookup


    class MultiValueCharFilter(filters.BaseCSVFilter, filters.CharFilter):

        def filter(self, qs, value):
            # value is either a list or an 'empty' value
            values = value or []

            print(values)

            for value in values:
                qs = super(MultiValueCharFilter, self).filter(qs, value) | qs
            return qs

class ProductListFilter(filters.FilterSet):
    min_price = filters.NumberFilter(name="price", lookup_expr='gte')
    max_price = filters.NumberFilter(name="price", lookup_expr='lte')
    category_name_fr = MultiValueCharFilter(name="category_name_fr", lookup_expr='icontains')
    category_name_en = MultiValueCharFilter(name="category_name_en", lookup_expr='icontains')
    collection_name_fr = MultiValueCharFilter(name="collection_name_fr", lookup_expr='icontains')
    collection_name_en = MultiValueCharFilter(name="collection_name_en", lookup_expr='icontains')
    name_en = MultiValueCharFilter(name="name_en", lookup_expr='icontains')
    name_fr = MultiValueCharFilter(name="name_fr", lookup_expr='icontains')

    class Meta:
        model = ProductList
        fields = ['sale', 'sold', 'min_price', 'max_price', 'category_name_fr', 'name_en', 'name_fr', 
        'category_name_en', 'collection_name_fr', 'collection_name_en']

For more infos this is the code of the view ListAPIView

from rest_framework import viewsets, generics, filters as rf_filters
from ..models import Product,  Collection, ProductList
from ..serializers import ProductSerializer, CollectionSerializer, ProductListSerializer
from django_filters import rest_framework as filters
from ..filters import ProductFilter, ProductListFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from rest_framework.response import Response


class StandardResultsSetPagination(PageNumberPagination):
    page_size = 4
    page_size_query_param = 'page_size'
    max_page_size = 15

class ProductList(generics.ListAPIView):
    queryset = ProductList.objects.all()
    serializer_class = ProductListSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = ProductListFilter
    serializer_class = ProductListSerializer
    ordering_fields = ('price', 'created_at')
    pagination_class = StandardResultsSetPagination

Upvotes: 6

Views: 4409

Answers (2)

Abhi
Abhi

Reputation: 1

Views.py

class ApplicationListAPIView(generics.ListAPIView):
    .......
    filter_backends = (DjangoFilterBackend,)
    filter_class = ApplicationFilters
    ......etc

filters.py

from django_filters import FilterSet
from .models import Application

class ApplicationFilters(FilterSet):

    class Meta:
        model = Application
        fields = {
            'evaluation_type':["in"],
            'purpose':["in"],
            'board':["in"]
        } 

Now,url should be like: http://127.0.0.1:8000/api/application?purpose__in=1,2,3

http://127.0.0.1:8000/api/application?evaluation_type__in=type1,type2

http://127.0.0.1:8000/api/application?board__in=board1,board2,board3,board4

Upvotes: 0

anjaneyulubatta505
anjaneyulubatta505

Reputation: 11695

You need to write a custom filter & filterset class like below

filterset.py

from django_filters import Filter, FilterSet
from django_filters.constants import EMPTY_VALUES

class ListFilter(filters.Filter):
    def filter(self, qs, value):
        if value in EMPTY_VALUES:
            return qs
        value_list = value.split(",")
        qs = super().filter(qs, value_list)
        return qs

class ProductListFilter(filters.FilterSet):
    category_name_fr = ListFilter(field_name="category_name_fr", lookup_expr="in")
    # other fields

views.py

from django_filters.rest_framework import DjangoFilterBackend

class ProductList(generics.ListAPIView):
  filter_backends = (DjangoFilterBackend,)
  filterset_class = ProductListFilter
  # other attr settings

Ref: https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html#adding-a-filterset-with-filterset-class

Upvotes: 3

Related Questions