Reputation: 65
I'd like all my filters to route to a single method, so I can look at each and decide logic based on which ones are set. I have this working, but each filter is now calling the same method once, leading below code to print hi
4 times.
Is there a best practice way to route all filters to a single method? I'd like hi
to be only printed once here, and wondering if I can avoid using a hacky solution.
class CityFilter(FilterSet):
start_date_i = django_filters.DateTimeFilter(field_name='dept_date', method='filter_city')
start_date_j = django_filters.DateTimeFilter(field_name='dept_date', method='filter_city')
end_date_i = django_filters.DateTimeFilter(field_name='ret_date', method='filter_city')
end_date_j = django_filters.DateTimeFilter(field_name='ret_date', method='filter_city')
class Meta:
model = models.City
def filter_city(self, queryset, name, value):
print('hi')
data = self.data
sdate_i = data.get('start_date_i')
sdate_j = data.get('start_date_j')
edate_i = data.get('end_date_i')
edate_j = data.get('end_date_j')
# do expensive stuff and build queryset from all filter name / values
return queryset
Upvotes: 0
Views: 843
Reputation: 21822
You can try combining the fields and hence the filter into one using the MultiValueField
[Django docs] and SuffixedMultiWidget
[django-filter docs]:
from django import forms
from django_filters import Filter
from django_filters.widgets import SuffixedMultiWidget
class QuadDateTimeWidget(SuffixedMultiWidget):
'''A widget that combines 4 `DateTimeInput` widgets'''
suffixes = ['start_i', 'start_j', 'end_i', 'end_j']
def __init__(self, attrs=None):
widgets = [
forms.DateTimeInput(),
forms.DateTimeInput(),
forms.DateTimeInput(),
forms.DateTimeInput(),
]
super().__init__(widgets, attrs):
def decompress(self, value):
# Need a list of values to be able to pass to children widgets
if value:
value = list(value)
value.extend([None] * (4 - len(value)))
return value
return [None, None, None, None]
class QuadDateTimeField(forms.MultiValueField):
'''A form field that uses 4 `DateTimeField` instances'''
widget = QuadDateTimeWidget
def __init__(self, fields=None, *args, **kwargs):
if fields is None:
fields = (
forms.DateTimeField(),
forms.DateTimeField(),
forms.DateTimeField(),
forms.DateTimeField()
)
super().__init__(fields, *args, **kwargs)
def compress(self, data_list):
# You can change this to a dictionary for simpler use if needed, although remember to change `decompress` in the widget above to return a list of the values in that case
if data_list:
return list(data_list)
return [None, None, None, None]
class QuadDateTimeFilter(Filter):
'''A filter that uses QuadDateTimeField'''
field_class = QuadDateTimeField
def filter(self, qs, value):
# You can also filter here if needed, you can get the `field_name` parameter by using `self.field_name`
raise NotImplementedError("Implement the method on the FilterSet class")
class CityFilter(FilterSet):
date = QuadDateTimeFilter(field_name='dept_date', method='filter_city')
def filter_city(self, queryset, name, value):
print('hi')
sdate_i = value[0]
sdate_j = value[1]
edate_i = value[2]
edate_j = value[3]
# do expensive stuff and build queryset from all filter name / values
return queryset
Upvotes: 1