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

时间:2017-12-20 10:36:55

标签: django django-filter

给定一个像这样的过滤器:

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的方法,以便我可以将{0}放入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)

1 个答案:

答案 0 :(得分:1)

我在下面留下了我原来的答案,但更简单的选择是将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)

这是一个不寻常的案例。过滤通常是一个减法过程,但这里它是附加的。虽然您当前的解决方案可能会感到笨拙,但确实如此 有效。我要做的唯一更改是从表单cleaned_data中提取值而不是从未处理的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)