Django QuerySet.union() - 或 - QuerySet.raw()实现不区分大小写的多重搜索

时间:2018-01-14 18:19:53

标签: python django django-queryset case-insensitive

给出这样的网址:

http://..../search/?foo=a&foo=B&bar=whatever

在我的视图中,我想过滤QuerySet以获取“foo”的CASE-INSENSITIVE匹配。我可以在我的“foo”列表中使用一个方便的“in”运算符,但它不支持不区分大小写。

要清楚,此(优雅代码)执行CASE-SENSITIVE匹配。 (它与“foo = b”不匹配。)我不想要这个:

    queryset = queryset.filter(foo__in=role)  # case-sensitive

我的解决方案是创建一个QuerySets列表,每个“foo”匹配一个,然后创建返回结果的最终“union()”。

def get_queryset(self, **kwargs):
  queryset = super(PeopleListView, self).get_queryset()

  foo = self.request.GET.getlist('foo')
  if (len(foo) == 1):
    queryset = queryset.filter(foo__iexact=role[0])  # case-insensitive
  elif (len(foo) > 1):
    qs_list = []
    for _foo in foo:
      qs_list.append(queryset.filter(foo__iexact=_foo))
    queryset = Person.objects.none()  # EmptyQuerySet
    for qs in qs_list:
      queryset = queryset.union(qs)

  bar = self.request.GET.get('bar')
  if bar is not None:
    queryset = queryset.filter(bar__iexact=bar)  # Easy

这会导致错误:

django.db.utils.DatabaseError: ORDER BY not allowed in subqueries of compound statements.

有没有办法用“Q”对象做到这一点?

如果没有,我认为“正确”的解决方案将涉及将匹配模式转换为小写,然后使用QuerySet :: raw()将数据库值转换为小写。我在那里有点过头了......

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

嗯,这是答案。使用“Q”对象! : - )

...
foo = self.request.GET.getlist('foo')
if (len(foo) > 0):
  q = Q()
  for _foo in foo:
    q |= Q(foo__iexact=_foo)
  queryset = queryset.filter(q)
...

哦,并支持这样的匹配网址:

http://..../fl/users/?foo=&bar=some_bar

这使得:

<QueryDict: {'foo': [''], 'bar': ['some_bar']}>

我会这样做:

...
foo = self.request.GET.getlist('foo')
if (len(foo) > 0):
  q = Q()
  for _foo in foo:
    if (_foo == ''):
      q |= Q(foo=None)
    else:
      q |= Q(foo__iexact=_foo)
  queryset = queryset.filter(q)
...