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