给定这样的过滤器集:
class MyFilter(django_filters.rest_framework.FilterSet):
include_unusual_entries = django_filters.BooleanFilter(method='noop')
我希望"默认"查询集为
MyModel.objects.exclude(unusual_state=True)
并且仅当设置了include_unusual_entries
过滤器时,我希望查询集是
MyModel.objects.all()
我是否缺少解决此问题的明显方法?我没有看到在过滤器上设置invert=True
的方法,也没有办法设置always_filter
以便我可以将 if 放入method
中。
现在,我通过覆盖过滤器集上的qs
属性来解决它,但感觉很不对劲:
@property
def qs(self):
queryset = super(MyFilter, self).qs
if 'include_unusual_entries' in self.data: # if inclusion is explcitly enabled
return queryset
else: # if inclusion is *not* explicitly enabled (the default)
return queryset.exclude(unusual_state=True)
我在下面留下了我的原始答案,但一个更简单的选择是将method
与CheckboxInput
相结合,这不区分空假。实际上,除非另有说明,否则它默认为 false。这是CheckboxInput
实际上合适的少数情况之一。
class MyFilter(filters.FilterSet):
include_unusual_entries = filters.BooleanFilter(
method='filter_unusual_entries',
widget=forms.CheckboxInput,
)
def filter_unusual_entries(self, qs, name, value):
return qs if value else qs.exclude(unusual_state=True)
这是一个有点不寻常的情况。过滤通常是一个减法过程,但在这里它是累加的。虽然您当前的解决方案可能感觉很笨拙,但它是 有效。我要做的唯一更改是从未处理的data
查询字典中提取值,而不是从表单的cleaned_data
中提取值。
if self.cleaned_data.get('include_unusual_entries', False):
return queryset
也就是说,一些替代解决方案:
强制使用默认值
from django_filters import rest_framework as filters
from django_filters.constants import EMPTY_VALUES
class MyFilter(filters.FilterSet):
include_unusual_entries = filters.BooleanFilter(method='filter_unusual_entries')
def __init__(self, data=None, *args, **kwargs):
if data is not None: # if filterset is bound, force default value
data = data.copy() # get a mutable copy of the QueryDict
if data.get('include_unusual_entries', None) in EMPTY_VALUES:
data['include_unusual_entries'] = False
super().__init__(data, *args, **kargs)
def filter_unusual_entries(self, name, qs, value):
return qs if value else qs.exclude(unusual_state=True)
相似,但有filter_queryset()
覆盖.qs
属性一直有点尴尬。虽然它仍在开发中,但 django-filter 2.x 解决了这个问题。相反,您将覆盖filter_queryset()
.
from django_filters import rest_framework as filters
from django_filters.constants import EMPTY_VALUES
class MyFilter(filters.FilterSet):
include_unusual_entries = filters.BooleanFilter(method='noop')
def filter_queryset(self, queryset):
if not self.form.cleaned_data.get('include_unusual_entries', False):
queryset = queryset.exclude(unusual_state=True)
return super().filter_queryset(queryset)