Django查询不区分大小写的列表匹配

dra*_*oon 34 django django-queryset

我有一个名称列表,我想匹配不区分大小写,有没有办法在不使用下面的循环的情况下执行此操作?

a = ['name1', 'name2', 'name3']
result = any([Name.objects.filter(name__iexact=name) for name in a])
Run Code Online (Sandbox Code Playgroud)

Ras*_*Kaj 40

不幸的是,没有 __iin字段查找.但有一个iregex可能有用,如下:

result = Name.objects.filter(name__iregex=r'(name1|name2|name3)')
Run Code Online (Sandbox Code Playgroud)

甚至:

a = ['name1', 'name2', 'name3']
result = Name.objects.filter(name__iregex=r'(' + '|'.join(a) + ')')
Run Code Online (Sandbox Code Playgroud)

请注意,如果a可以包含正则表达式中特殊的字符,则需要正确转义它们.

新闻:在Djano 1.7中,可以创建自己的查找,因此您可以filter(name__iin=['name1', 'name2', 'name3'])在正确初始化后实际使用.有关详细信息,请参阅https://docs.djangoproject.com/en/1.7/ref/models/lookups/.

  • 我希望他们实施__iin (8认同)
  • Postgres支持不区分大小写的索引,因此对于这种情况,为每个项目运行单独的"iexact"查询可能比iregex匹配更快.在django的postgres后端"iexact"搜索使用UPPER()变换,因此对于该行的UPPER()自定义索引,可以获得加速. (2认同)
  • 对于所有简单复制此答案的人:还有两件事需要考虑:(1)正则表达式转义,如@Martin Smith在下面进一步提到的,以及(2)如果您想要一个 __in 运算符,请确保您正在使用 start和结束分隔符 `result = Name.objects.filter(name__iregex=r'^(' + '|'.join([re.escape(b) for b in a]) + ')$')` (2认同)

Evg*_*eny 21

在Postgresql中,您可以尝试创建不区分大小写的索引,如下所述:

/sf/answers/288695781/

然后运行查询:

from django.db.models import Q
name_filter = Q()
for name in names:
    name_filter |= Q(name__iexact=name)
result = Name.objects.filter(name_filter)
Run Code Online (Sandbox Code Playgroud)

索引搜索将比正则表达式匹配查询运行得更快.

  • 注意这个代码!如果变量名为空,则.filter将返回该模型的所有对象! (4认同)

Noo*_*aja 16

使用django查询函数 和注释的另一种方法

from django.db.models.functions import Lower
Record.objects.annotate(name_lower=Lower('name')).filter(name_lower__in=['two', 'one']
Run Code Online (Sandbox Code Playgroud)


小智 5

添加到 Rasmuj 所说的,像这样转义任何用户输入

import re
result = Name.objects.filter(name__iregex=r'(' + '|'.join([re.escape(n) for n in a]) + ')')
Run Code Online (Sandbox Code Playgroud)


m00*_*000 5

请记住,至少在 MySQL 中,您必须utf8_bin在表中设置排序规则以实际使它们区分大小写。否则,它们保留大小写但不区分大小写。例如

>>> models.Person.objects.filter(first__in=['John', 'Ringo'])
[<Person: John Lennon>, <Person: Ringo Starr>]
>>> models.Person.objects.filter(first__in=['joHn', 'RiNgO'])
[<Person: John Lennon>, <Person: Ringo Starr>]
Run Code Online (Sandbox Code Playgroud)

因此,如果可移植性并不重要并且您使用 MySQL,您可以选择完全忽略该问题。