Django 查询不区分大小写的数据

Django Query with Case Insensitive Data Both Ways

有很多类似的问题,但我只找到了部分解决方案。 我有一组用户存储为对象,具有名称属性 (User.name)。我希望使用用户输入 (Foo) 进行查询,这样我就可以(不区分大小写)找到所有用户:

  1. foo 在 User.name
  2. User.name 在 foo

例如,我希望用户能够输入 "Jeff William II" 和 return "Anderson Jeff William II"、"jeff william iii" 以及 "Jeff Will"和 "william ii"

我知道我可以使用 Q function 组合两个查询,我可以使用 annotate() 像这样转换 User.name (如果您发现此代码中的错误,我欢迎您进行编辑) :

users = User.objects.annotate(name_upper=Upper(name)).filter(Q(name_upper__icontains=foo) | Q(name_upper__in=foo))

但是我 运行 在使用 __in 匹配字符串中的多个字母时遇到了麻烦。因此,如果 User.name 是 "F",我在输入 Jeff 时会被击中,但如果 User.name 是 "JE",那么它不会显示。如何匹配多个字母,或者是否有更好的方法来进行此查询?

旁注:我最初使用以下方法解决了这个问题,但如果可能的话我更愿意进行查询。

for u in User.objects.all():
     if u.name in foo or foo in u.name:

不要使用Upper。一个常见的误解是,通过将两个项目转换为大写(或小写),您进行了不区分大小写的相等性检查。某些字符,如 ß 没有 uppercase/lowercase,并且有更复杂的规则(整理)来考虑这些等价物。在 Python 中,人们使用 .casefold(…) [python-doc]

对于数据库,你可以简单地使用注释,然后使用两个检查:

from django.db.models import CharField, F, Q, Value

foo = 'Jeff William II'

User.objects.annotate(<b>foo=Value(foo, CharField())</b>).filter(
    Q(name__icontains=<b>foo</b>) | Q(<b>foo__icontains=F('name')</b>)
)