Reputation: 13
I'm a beginner and develop a little REST API project with Django rest framework. There are a bunch of records in PostgreSQL database with a text field and I have some lists of keywords. I'm trying to filter data which contain words from one or some my lists of keywords in this text field.
Can you advise me another way around to organize filtering in DRF by using a whole list of keywords at once without entering them in a form?
I'm trying to do it with django_filters
Here if filter class:
# filter
class DataFilter(django_filters.rest_framework.FilterSet):
keyword = CharFilter(field_name='description', lookup_expr='icontains')
class Meta:
model = Data
fields = ('keyword', )
Here if view class:
# view
class DataList(generics.ListAPIView):
def get_queryset(self):
return Data.objects.filter(deadline__gte=date.today())
serializer_class = DataSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = DataFilter
But in this case, it filters only by one word which I enter in the form.
Upvotes: 1
Views: 2639
Reputation: 159
In my case, I need to filter by multiple keywords and after to exclude from the filtered qs another set of keywords.
Something like base_url/?kwords=kw1,kw2,kw3&exclude=e_kw1,e_kw2&others....
Inheriting from filters.BaseInFilter
did not work for me... it is strange since BaseInFilter inherits from BaseCSVFilter, or I made a mistake.
My solution:
from django.db.models import Q
from django_filters import rest_framework as filters
from products.models import Product
class KwordIncludeFilter(filters.BaseCSVFilter):
def filter(self, qs, values):
query = Q()
if not values:
return qs
else:
for value in values:
value = value.strip()
query |= Q(name__icontains=value)
qs = qs.filter(query)
return qs
class KwordExcludeFilter(filters.BaseCSVFilter):
def filter(self, qs, values):
query = Q()
if not values:
return qs
else:
for value in values:
value = value.strip()
query |= Q(name__icontains=value)
qs = qs.exclude(query)
return qs
class ProductFilter(filters.FilterSet):
kwords = KwordIncludeFilter()
exclude = KwordExcludeFilter()
class Meta:
model = Product
fields = {
'some_other_model_filed': ['some_lookup']
}
Upvotes: 0
Reputation: 51988
I think you can do it like this:
First, create a new filter set subclassing from BaseInFilter and CharFilter
:
class CharInFilter(django_filters.BaseInFilter, django_filters.CharFilter):
pass
Then, update your FilterSet class like this:
class DataFilter(django_filters.FilterSet):
keyword__in = CharInFilter(field_name='keyword', lookup_expr='in')
class Meta:
model = Data
fields = []
Then you can use this FilterSet(same as your current implementation) like this:
class DataList(generics.ListAPIView):
def get_queryset(self):
return Data.objects.filter(deadline__gte=date.today())
serializer_class = DataSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = DataFilter
While using this filterset in DRF template, you need to input your values in comma separated format, like this:
Upvotes: 1