Open nimame opened 3 years ago
I ended up adding a mixin that overwrites the filter_queryset
method of the FilterSet
class, based on the solution suggested here and here.
from django.db.models import QuerySet
from django_filters.constants import EMPTY_VALUES
from rest_framework_filters import FilterSet
class FilterSetMixin:
def filter_queryset(self, queryset):
"""
Overrides the basic method, so that instead of iterating over the queryset with multiple `.filter()`
calls, one for each filter, it accumulates the lookup expressions and applies them all in a single
`.filter()` call - to filter with an explicit "AND" in many to many relationships.
"""
filter_kwargs = {}
for name, value in self.form.cleaned_data.items():
if value not in EMPTY_VALUES:
lookup = '%s__%s' % (self.filters[name].field_name, self.filters[name].lookup_expr)
filter_kwargs.update({lookup: value})
queryset = queryset.filter(**filter_kwargs)
assert isinstance(queryset, QuerySet), \
"Expected '%s.%s' to return a QuerySet, but got a %s instead." \
% (type(self).__name__, name, type(queryset).__name__)
queryset = self.filter_related_filtersets(queryset)
return queryset
class BlogFilterSet(FilterSetMixin, FilterSet):
class Meta:
model = Blog
fields = {
'entry__headline': ['contains'],
'entry__pub_date': ['year__exact']
}
class BlogViewSet(viewsets.ModelViewSet):
serializer_class = BlogSerializer
filter_backends = (RestFrameworkFilterBackend, )
filterset_class = BlogFilterSet
It feels like this should be the default behavior. But maybe I'm missing something.
Is there are any better way?
In my DRF project, I'm trying to implement filtering for multi-valued relationships that combines filters with logical
AND
s, like in:a)
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
instead of
OR
like in:b)
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
The following results in b):
Is there a way to get a) without specifying the filter explicitly? If no, could someone provide an example for the explicit filter based on the one I provided?
Thank you.