这是一个django-filter应用专用猜测。
是否有人试图根据条件为过滤器引入条件?
让我举个例子:
假设我们有一个Product
模型。它可以根据name
和price
进行过滤。
默认的django-filter
行为是,当我们使用更多过滤器并将它们链接在一起时,它们会使用AND
语句过滤数据(它会缩小搜索范围)。
我想更改此行为并添加ChoiceFilter,例如有两个选项:AND
以及OR
。从这一点来说,过滤器应该根据用户选择的内容工作。
EG。如果用户使用name__startswith="Juice"
OR
price__lte=10.00
查询产品,则应列出名称以Juice
开头的所有产品以及价格低于10.00
的产品。
Django-filter
文档说过滤器可以带参数:
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.
这似乎是我正在寻找的,但文档缺乏任何进一步的解释。建议好吗?
@EDIT:
这是views.py
:
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render_to_response('my_app/template.html', {'filter': f})
答案 0 :(得分:2)
action
不会削减它。此回调用于特定过滤器字段,只能访问该字段的值。
最干净的方法是创建多小部件过滤器字段,类似于RangeField
。查看source。
因此,您使用name
,price
和逻辑类型[AND|OR]
两个日期字段作为字段,这样您就可以一次访问所有这些值以在自定义查询集中使用。
编辑1:
我写这篇文章是为了展示如何使用所选运算符查询两个字段。 https://gist.github.com/mariodev/6689472
用法:
class ProductFilter(django_filters.FilterSet):
nameprice = NamePriceFilter()
class Meta:
model = Product
fields = ['nameprice']
它在重复使用方面实际上不是很灵活,但肯定可以重新考虑以使其有用。
答案 1 :(得分:2)
由于构造最终查询集的方式,使每个过滤器进行OR运算很困难。基本上,代码的工作原理如下:
FilterSet,filterset.py line 253:
@property def qs(self): qs = self.queryset.all() for filter_ in self.filters(): qs = filter_.filter(qs)
过滤器,filters.py line 253:
def filter(self, qs): return qs.filter(name=self.value)
每个过滤器可以决定如何将自身应用于传入的查询集,并且当前实现的所有过滤器都使用AND过滤传入的查询集。您可以为传入的查询集创建一组新的过滤器,但是无法覆盖FilterSet端的行为。
答案 2 :(得分:1)
为了使过滤器与OR一起工作,你应该创建一个FilterSet的子类,并从Tim的答案中覆盖qs,如下所示:
@property
def qs(self):
qs = self.queryset.none()
for filter_ in self.filters():
qs |= filter_.filter(self.queryset.all())
我没有对此进行测试,但我认为你有了这个想法。 QuerySets支持按位操作,因此您可以轻松地将两个过滤器的结果与OR结合起来。
答案 3 :(得分:1)
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