Django QuerySet.union() -or- QuerySet.raw() 实现不区分大小写的多重搜索
Django QuerySet.union() -or- QuerySet.raw() to Achieve Case-Insensitive Mutli-Search
给出这样的 URL:
http://..../search/?foo=a&foo=B&bar=whatever
在我看来,我想为 "foo" 的不区分大小写的匹配项过滤查询集。我可以在我的 "foo" 列表中使用一个方便的 "in" 运算符,但它不支持不区分大小写。
明确地说,这个(优雅的代码)执行了区分大小写的匹配。 (它不匹配 "foo=b"。)我不想要这个:
queryset = queryset.filter(foo__in=role) # case-sensitive
我的解决方案是创建一个查询集列表,每个 "foo" 匹配一个,然后创建 return 结果的最终 "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" 个对象执行此操作?
如果不是,我认为 "right" 解决方案将涉及将匹配模式转换为小写,然后使用 QuerySet::raw() 将数据库值也转换为小写。我有点头晕了...
感谢您的帮助!
好吧,这就是答案。使用 "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)
...
哦,要支持这样的匹配 URL:
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)
...
给出这样的 URL:
http://..../search/?foo=a&foo=B&bar=whatever
在我看来,我想为 "foo" 的不区分大小写的匹配项过滤查询集。我可以在我的 "foo" 列表中使用一个方便的 "in" 运算符,但它不支持不区分大小写。
明确地说,这个(优雅的代码)执行了区分大小写的匹配。 (它不匹配 "foo=b"。)我不想要这个:
queryset = queryset.filter(foo__in=role) # case-sensitive
我的解决方案是创建一个查询集列表,每个 "foo" 匹配一个,然后创建 return 结果的最终 "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" 个对象执行此操作?
如果不是,我认为 "right" 解决方案将涉及将匹配模式转换为小写,然后使用 QuerySet::raw() 将数据库值也转换为小写。我有点头晕了...
感谢您的帮助!
好吧,这就是答案。使用 "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)
...
哦,要支持这样的匹配 URL:
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)
...