web-dev-qa-db-ja.com

Django大文字と小文字を区別しないリストの一致をクエリ

大文字と小文字を区別せずに一致させたい名前のリストがありますが、以下のようなループを使用せずにそれを行う方法はありますか?

a = ['name1', 'name2', 'name3']
result = any([Name.objects.filter(name__iexact=name) for name in a])
38
dragoon

残念ながら、no___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) + ')')
_

正規表現で特別な文字を含むことができる場合は、それらを適切に escape する必要があることに注意してください。

ニュース:Djano 1.7では、独自のルックアップを作成できるため、適切に初期化した後、実際にfilter(name__iin=['name1', 'name2', 'name3'])を使用できます。詳細については、 https://docs.djangoproject.com/en/1.7/ref/models/lookups/ を参照してください。

43
Rasmus Kaj

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)

インデックス検索は、正規表現マッチングクエリよりも高速に実行されます。

24
Evgeny

Djangoクエリ関数 とアノテーションを使用してこれを行う別の方法

from Django.db.models.functions import Lower
Record.objects.annotate(name_lower=Lower('name')).filter(name_lower__in=['two', 'one']
17
Noortheen Raja

少なくとも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を使用している場合は、問題を完全に無視することを選択できます。

5
m000

Rasmujが言ったことに加えて、そのようなユーザー入力をエスケープします

import re
result = Name.objects.filter(name__iregex=r'(' + '|'.join([re.escape(n) for n in a]) + ')')
4
Martin Smith

Exgenyのアイデアを2つのライナーに拡張しています。

import functools
Name.objects.filter(functools.reduce(lambda acc,x: acc | Q(name_iexact=x)), names, Q()))
2
user1462442

これは、ユーザーをフィルタリングするためのカスタムユーザーモデル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)
1
pymen