2013-09-22 37 views
1

这是一个django-filter特定于应用程序的问题。改变Django过滤默认行为

有没有人试图引入过滤条件来根据条件进行查询?

让我举一个例子:

假设我们有一个Product模型。它可以根据其nameprice进行过滤。

默认django-filter的行为是,因为我们使用更多的过滤器并将它们链接在一起,所以它们使用AND语句(它缩小了搜索范围)过滤数据。

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

例如,如果用户查询含有name__startswith="Juice"ORprice__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}) 

回答

2

action将不会削减它。此回调用于特定的筛选字段,并且只能访问该字段的值。

最简洁的方法是创建多窗口小部件过滤器字段,类似于RangeField。检查出source

所以不是两个日期字段使用nameprice和逻辑型[AND|OR]的领域,这样你在一次访问所有这些值在自定义查询集使用。

编辑1:

这是一个小要点我写来展示如何查询与选择的运营商两个字段。 https://gist.github.com/mariodev/6689472

用法:

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

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

它实际上不是在重新使用方面非常灵活,但肯定可以重新分解,使有益。

+0

感谢您对此问题的关注。你能给出一个快速代码的例子吗?我想我不知道如何将这个'[AND | OR]'逻辑类型用作字段。 – nutship

+0

@shipship我会用自己的代码更新我的帖子(因为我也对这个问题感兴趣)。 '[AND | OR]'表示为无线电或选择字段,只要将其视为典型的过滤字段并使用它的值构造AND或OR查询集。 – mariodev

+0

谢谢。啊,所以基本上我们构造一个查询集是'views.py',然后传递给''queryset'变量(而不是默认的'Product.objects.all()')? – nutship

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方面的行为。

1

为了使过滤器工作或,你应该让蒂姆的回答类似这样的FilterSet和覆盖QS的一个子类:

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

我没有测试过这一点,但我觉得你有这个想法。 QuerySets支持按位操作,因此您可以轻松地将两个过滤器的结果与OR组合。

+0

谢谢你们花时间回复。我将不得不花上一两天的时间,希望能让它工作。 – nutship

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 
 
+0

向你的代码添加一些解释。 –