如何否定/反转 django 过滤器(排除*除非*过滤器处于活动状态)?



给定这样的过滤器集:

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)

我在下面留下了我的原始答案,但一个更简单的选择是将methodCheckboxInput相结合,这不区分空假。实际上,除非另有说明,否则它默认为 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)

最新更新