Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 改变django过滤器的默认行为_Python_Django_Django Filter - Fatal编程技术网

Python 改变django过滤器的默认行为

Python 改变django过滤器的默认行为,python,django,django-filter,Python,Django,Django Filter,这是特定于应用程序的留言 是否有人试图根据条件为过滤器引入查询条件 让我举一个例子: 假设我们有一个产品模型。它可以根据其名称和价格进行过滤 默认的django过滤器行为是,当我们使用更多过滤器并将它们链接在一起时,它们使用和语句过滤数据(这缩小了搜索范围) 我想改变这种行为并添加一个ChoiceFilter,比如说有两个选项:和以及或。从这一点来看,过滤器应该根据用户选择的内容工作 例如,如果用户查询带有name\uu startswith=“Juice”或price\uu lte=10.00

这是特定于应用程序的留言

是否有人试图根据条件为过滤器引入查询条件

让我举一个例子:

假设我们有一个
产品
模型。它可以根据其
名称
价格
进行过滤

默认的
django过滤器
行为是,当我们使用更多过滤器并将它们链接在一起时,它们使用
语句过滤数据(这缩小了搜索范围)

我想改变这种行为并添加一个ChoiceFilter,比如说有两个选项:
以及
。从这一点来看,过滤器应该根据用户选择的内容工作

例如,如果用户查询带有
name\uu startswith=“Juice”
price\uu lte=10.00
的产品,则应列出名称以
Juice
开头的所有产品以及价格低于
10.00
的产品

Django过滤器
文档说过滤器可以接受一个参数:

action

An optional callable that tells the filter how to handle the queryset. It recieves a 
QuerySet and the value to filter on and should return a Queryset that is filtered 
appropriately.
这似乎是我要找的,但文件中没有任何进一步的解释。有什么建议吗

@编辑:

这是
views.py

def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    return render_to_response('my_app/template.html', {'filter': f})

操作
无法将其删除。此回调用于特定的筛选器字段,并且只能访问该字段的值

最干净的方法是创建多窗口小部件过滤器字段,类似于
RangeField
。看看这本书

因此,您可以使用两个日期字段作为字段使用
name
price
和逻辑类型
[和|或]
,这样您就可以一次访问所有这些值,以便在自定义查询集中使用

编辑1:

这是我写的一个小要点,展示了如何使用所选运算符查询两个字段。

用法:

class ProductFilter(django_filters.FilterSet):
    nameprice = NamePriceFilter()

    class Meta:
        model = Product
        fields = ['nameprice']

实际上,就重用而言,它不是很灵活,但当然可以对其进行重新分解以使其有用。

由于最终查询集的构造方式,很难将每个筛选器进行OR运算。基本上,代码是这样工作的:

@property
def qs(self):
    qs = self.queryset.none()
    for filter_ in self.filters():
        qs |= filter_.filter(self.queryset.all())
过滤器集:

@财产 def qs(自我): qs=self.queryset.all() 对于self.filters()中的过滤器: qs=过滤器\过滤器(qs) 过滤器:

def过滤器(自身、qs): 返回qs.filter(name=self.value)
每个过滤器可以决定如何将自身应用于传入的queryset,而当前实现的所有过滤器都使用and过滤传入的queryset。您可以创建一组新的筛选器,这些筛选器或其自身将添加到传入的queryset中,但无法从FilterSet端重写该行为。

为了使筛选器与或一起工作,您应该创建FilterSet的子类,并按照Tim的回答重写qs,如下所示:

@property
def qs(self):
    qs = self.queryset.none()
    for filter_ in self.filters():
        qs |= filter_.filter(self.queryset.all())

我还没有测试过这个,但我想你已经知道了。查询集支持按位运算,因此您可以轻松地将两个过滤器的结果与或组合起来。

感谢您对这个问题的关注。您能给出一个快速的代码示例来说明这是什么样子吗?我想我不知道如何使用这个
[和|或]
逻辑类型作为字段。@nutship当我自己编写代码时,我会用示例更新我的文章(因为我也对这个问题感兴趣)<代码>[和|或]
表示为radio或select字段,只需将其视为典型的过滤器字段,并使用其值来构造AND或queryset。谢谢。啊,所以基本上我们构造一个queryset是
views.py
,然后将它传递给
queryset
变量(而不是默认的
Product.objects.all()
)?@nutship不,不,你搞错了,这是内部过滤器字段queryset,它只是整个queryset的一部分。只要看看
RangeField
src,试着理解它是如何工作的,或者等到我用这个代码片段更新我的帖子。我宁愿以某种方式重写
FilterSet
,但实际上没有一个好的重写方法。您可以使用
qs
方法,但这将是大量重复的代码…感谢您花时间回复。我必须花一两天的时间来处理这个问题,希望能让它发挥作用。



class FileFilterSet(django_filters.FilterSet):
    class Meta:
        model = File
        fields = ['project']

    def __init__(self, *args, **kwargs):
        super(FileFilterSet, self).__init__(*args, **kwargs)

        for name, field in self.filters.items():
            if isinstance(field, ModelChoiceFilter):
                field.extra['empty_label'] = None
                field.extra['initial'] = Project.objects.get(pk=2)
                # field.extra['queryset'] = Project.objects.filter(pk=2)


class FileFilter(FilterView):
    model = File
    template_name = 'files_list.html'
    filterset_class = FileFilterSet



class FileFilterSet(django_filters.FilterSet):
    class Meta:
        model = File
        fields = ['project']

    def __init__(self, *args, **kwargs):
        super(FileFilterSet, self).__init__(*args, **kwargs)

        for name, field in self.filters.items():
            if isinstance(field, ModelChoiceFilter):
                field.extra['empty_label'] = None
                field.extra['initial'] = Project.objects.get(pk=2)
                # field.extra['queryset'] = Project.objects.filter(pk=2)


class FileFilter(FilterView):
    model = File
    template_name = 'files_list.html'
    filterset_class = FileFilterSet