Reputation: 1142
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
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
Reputation: 11695
You need to write a custom filter & filterset class like below
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
from django_filters.rest_framework import DjangoFilterBackend
class ProductList(generics.ListAPIView):
filter_backends = (DjangoFilterBackend,)
filterset_class = ProductListFilter
# other attr settings
Upvotes: 3