【发布时间】:2011-02-09 16:26:20
【问题描述】:
我有一个要匹配不区分大小写的名称列表,有没有办法不使用下面的循环来做到这一点?
a = ['name1', 'name2', 'name3']
result = any([Name.objects.filter(name__iexact=name) for name in a])
【问题讨论】:
我有一个要匹配不区分大小写的名称列表,有没有办法不使用下面的循环来做到这一点?
a = ['name1', 'name2', 'name3']
result = any([Name.objects.filter(name__iexact=name) for name in a])
【问题讨论】:
不幸的是,没有 __iin 字段查找。但是有一个iregex 可能有用,如下所示:
result = Name.objects.filter(name__iregex=r'(name1|name2|name3)')
甚至:
a = ['name1', 'name2', 'name3']
result = Name.objects.filter(name__iregex=r'(' + '|'.join(a) + ')')
请注意,如果 a 可以包含正则表达式中的特殊字符,则需要正确地 escape 它们。
新闻:在 Django 1.7+ 中,可以创建自己的查找,因此您可以在正确初始化后实际使用 filter(name__iin=['name1', 'name2', 'name3'])。见documentation reference for details。
【讨论】:
result = Name.objects.filter(name__iregex=r'^(' + '|'.join([re.escape(b) for b in a]) + ')$')
在 Postgresql 中,您可以尝试创建一个不区分大小写的索引,如下所述:
https://stackoverflow.com/a/4124225/110274
然后运行查询:
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)
索引搜索将比正则表达式匹配查询运行得更快。
【讨论】:
使用django query functions 和注释的另一种方法
from django.db.models.functions import Lower
Record.objects.annotate(name_lower=Lower('name')).filter(name_lower__in=['two', 'one']
【讨论】:
Lower('name') 方式创建:stackoverflow.com/a/7005656/1236843
加上 Rasmuj 所说的,像这样转义任何用户输入
import re
result = Name.objects.filter(name__iregex=r'(' + '|'.join([re.escape(n) for n in a]) + ')')
【讨论】:
请记住,至少在 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>]
因此,如果可移植性并不重要并且您使用 MySQL,则可以选择完全忽略该问题。
【讨论】:
我正在将 Exgeny 的想法扩展到两个班轮。
import functools
Name.objects.filter(functools.reduce(lambda acc,x: acc | Q(name_iexact=x)), names, Q()))
【讨论】:
这是一个自定义用户模型 classmethod 的示例,用于过滤用户不区分大小写的电子邮件
from django.db.models import Q
@classmethod
def get_users_by_email_query(cls, emails):
q = Q()
for email in [email.strip() for email in emails]:
q = q | Q(email__iexact=email)
return cls.objects.filter(q)
【讨论】: