2011-11-12 184 views
2

我正在使用django-filter应用程序。然而,有一个问题我不知道如何解决。这几乎完全一样Django文档中描述了同样的事情:将几个过滤器组合成一个过滤器()与Django过滤器

https://docs.djangoproject.com/en/1.2/topics/db/queries/#spanning-multi-valued-relationships

我想打一个查询,我选择在标题“侬”的条目的所有博客是在2008年出版,如:

Blog.objects.filter(entry__headline__contains='Lennon', 
    entry__pub_date__year=2008) 

,不要选择在标题为“列侬”的条目并于2008年出版的另一入口(可能是相同的)博客:

Blog.objects.filter(entry__headline__contains='Lennon').filter(
    entry__pub_date__year=2008) 

然而,如果我设置过滤器,使得有两个字段(没关系__contains X __exact,只是一个例子):

class BlogFilter(django_filters.FilterSet): 
    entry__headline = django_filters.CharFilter() 
    entry__pub_date = django_filters.CharFilter() 

    class Meta: 
     model = Blog 
     fields = ['entry__headline', 'entry__pub_date', ] 

Django的过滤器将generete后者:

Blog.objects.filter(entry__headline__exact='Lennon').filter(
    entry__pub_date__exact=2008) 

有没有办法将两个过滤器合并到一个过滤器字段中?

+0

对不起,复活这种老线,但 'Foo.objects.filter(FOO = “酒吧”)过滤器(qux = “QUUX”) ' 实际上与 相同'Foo.objects.filter(foo =“bar”,qux =“quux”)' 多个关键字参数和随之而来的过滤器被“AND”编辑在一起。要创建“OR”过滤器,您必须使用'Q'对象:https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects – cvk

+0

@cvk hi ,根据https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships(包括dev和1.2版本)使用两个链接过滤器产生“选择所有包含在标题中加入“Lennon”的条目以及2008年发布的条目“但使用带有逗号的单一条款时,它会生成”选择包含标题为“Lennon”且2008年出版的条目的所有博客(满足两个条件的同一条目)“。这是一个巨大的差异。我还没有找到使用django-filter的方法 –

回答

1

那么,我来一个解决方案。使用常规的Django过滤器是不可能的,所以我扩展了一下。可能会有所改进,这是一个快速ñ肮脏的解决方案。

第一添加定制的“分组”字段django_filters.Filter和filter_grouped方法(几乎滤波方法的拷贝)

class Filter(object): 

    def __init__(self, name=None, label=None, widget=None, action=None, 
     lookup_type='exact', required=False, grouped=False, **kwargs): 
     (...) 
     self.grouped = grouped 

    def filter_grouped(self, qs, value): 
     if isinstance(value, (list, tuple)): 
      lookup = str(value[1]) 
      if not lookup: 
       lookup = 'exact' # we fallback to exact if no choice for lookup is provided 
      value = value[0] 
     else: 
      lookup = self.lookup_type 
     if value: 
      return {'%s__%s' % (self.name, lookup): value} 
     return {} 

的唯一的区别在于,而不是创建关于查询集的过滤器时,它返回一本字典。

第二更新BaseFilterSet适量方法/属性:

class BaseFilterSet(object): 
    (...) 
    @property 
    def qs(self): 
     if not hasattr(self, '_qs'): 
      qs = self.queryset.all() 
      grouped_dict = {} 
      for name, filter_ in self.filters.iteritems(): 
       try: 
        if self.is_bound: 
         data = self.form[name].data 
        else: 
         data = self.form.initial.get(name, self.form[name].field.initial) 
        val = self.form.fields[name].clean(data) 
        if filter_.grouped: 
         grouped_dict.update(filter_.filter_grouped(qs, val)) 
        else: 
         qs = filter_.filter(qs, val) 
       except forms.ValidationError: 
        pass 

      if grouped_dict: 
       qs = qs.filter(**grouped_dict) 

     (...) 
    return self._qs 

诀窍是存储在字典中的所有“分组”的过滤器,然后用它们作为所有单个滤波器。

过滤器将是这个样子,那么:。

class BlogFilter(django_filters.FilterSet): 
    entry__headline = django_filters.CharFilter(grouped=True) 
    entry__pub_date = django_filters.CharFilter(grouped=True) 

    class Meta: 
     model = Blog 
     fields = ['entry__headline', 'entry__pub_date', ]