Say I want to filter a built in django User
model, but I only want to do so in 1 filter field, instead of a filter per field. That is, I want to emulate behaviour that django admin's search_fields
(django admin search_fields docs), directly in the filter field.
Hence, for instance, instead of having a filter for field_name='first_name'
, then another filter for field_name'last_name'
and so forth, I want to do something like field_name=['first_name', 'last_name', 'email', 'username']
, where the same lookup_expr='icontains'
can be used. Then the query is a simple OR lookup. Is this built in? I couldn't find it in the django-filter docs.
Or do I have to make custom filter for this. It seems like a very common use case.
I did it with a custom filter using Q objects.
import django_filters
from django.db.models import Q
class UserFilter(django_filters.FilterSet):
multi_name_fields = django_filters.CharFilter(method='filter_by_all_name_fields')
class Meta:
model = User
fields = []
def filter_by_all_name_fields(self, queryset, name, value):
return queryset.filter(
Q(first_name__icontains=value) | Q(last_name__icontains=value) | Q(username__icontains=value) | Q(email__icontains=value)
)
Then make sure to filter against the new filter field (multi_name_fields) and that should return what you are looking for.
I have done something similar. This should help:
def filter_by_all_name_fields(self, queryset, name, value):
"""
Split the filter value into separate search terms and construct a set of queries from this. The set of queries
includes an icontains lookup for the lookup fields for each of the search terms. The set of queries is then joined
with the OR operator.
"""
lookups = ['first_name__icontains', 'last_name__icontains', 'username__icontains', 'email__icontains',]
or_queries = [Q(**{lookup: value}) for lookup in lookups]
return queryset.filter(reduce(operator.or_, or_queries))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With