"Django-filter" Is it possible to use FilterClass(FilterSet) MultipleChoiceFilter within ViewSet methods? Django 1.11, Python 2.7
I have my class ClassFilter(FilterSet)
with some of the Filters fx. MultipleChoiceFilter
, ModelMultipleChoiceFilter
etc. in it:
class ClassFilter(FilterSet):
something_severity = MultipleChoiceFilter(choices=Something.SEVERITY_CHOICES, method='something_severity_filter', widget=CSVWidget)
def something_severity_filter(self, queryset, name, severities):
if severities:
queryset = queryset.filter(something_state=Something.STATE_SOMETHING)
...
return queryset
class Meta:
model = Something
fields = []
It works perfect when it comes to filtering endpoints. It is assigned to the class like:
class ClassViewSet(mixins....., DefaultApiViewSet):
filter_class = ClassFilter
by having filter_class = ClassFilter
. Everything works just fine but now I am in in doubts if I may use the ClassFilter
MultipleChoiceFilter
within ClassViewSet
methods.
This means by executing POST
method in ClassViewSet
, I want to get the MultipleChoiceFilter
from FilterClass
to filter on my method by getting it as SomethingFilter.get_filters()
method
@action(detail=False, methods=['post'])
def something_update(self, req):
...
all_filters = SomethingFilter.get_filters()
for serializer_filter in serializer_filters:
for filter in all_filters:
if(serializer_filter == filter):
f = all_filters[filter]
Now the f
is a filter which I require so that is MultipleChoiceFilter
. But when I try to filter with that filter it throws an error.
f.filter(queryset, [('LOW')]) #filter the queryset with the filter based on LOW choice
Throws:
assertionError: Filter 'something_severity' must have a parent FilterSet to find '.something_severity_filter()'
In documentation for django-filter
it is exactly line: https://github.com/carltongibson/django-filter/blob/f4866a9852d569861651cc733f909fe0e378131b/django_filters/filters.py#L823
So my point is if there is a way to actually filter a method like this with a ClassFilter
like I have. If there is some other way how to actually do it correctly. I bet there is so I will not eventually have to do other filtering and keep the low-coupling.
If there is something that is not clearly said let me add towards this question! Thank you very much for every help.
So I have come back to the problem and come up with a solution.
When you have setup some filters that you need in FilterSet class(MultipleChoiceFilter,...)
class CarFilter(FilterSet):
wheel = MultipleChoiceFilter(choices=Wheel.CHOICES, method='wheel_filter', widget=CSVWidget)
def wheel_filter(self, queryset, name, cars):
if cars:
...
return queryset
class Meta:
model = Car
fields = []
You have to implement filter class in the ViewSet:
class CarViewSet(DefaultApiViewSet):
queryset = Car.objects.all()
serializer_class = CarSerializer
filter_class = CarFilter
You may use filter of your liking in the ViewSet methods when you set it like this:
IMPORTANT! - When using widget=CSVWidget
in MultipleChoiceFilter above, it works like that:
def car_method(self, req):
queryset = self.filter_queryset(self.get_queryset())
self.filter_class({"wheel": "MEDIUM,LOW"}, queryset).qs
When we are NOT using widget=CSVWidget
it works like that:
def car_method(self, req):
queryset = self.filter_queryset(self.get_queryset())
self.filter_class({'alert_severity': ['MEDIUM', 'LOW'], 'update_state': ['is_updated']}}, queryset).qs
Finished! We filtered cars based on their wheels.