"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.

Back to Top