Django запрос без учета регистра совпадения списка - PullRequest
30 голосов
/ 19 апреля 2010

У меня есть список имен, которые я хочу сопоставить без учета регистра, есть ли способ сделать это без использования цикла, как показано ниже?

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

Ответы [ 7 ]

35 голосов
/ 19 апреля 2010

К сожалению, есть поиск полей 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) + ')')

Обратите внимание, что если a может содержать символы, которые являются специальными в регулярном выражении, вам нужно экранировать их правильно.

NEWS: в Djano 1.7 можно создавать свои собственные поиски, поэтому вы можете использовать filter(name__iin=['name1', 'name2', 'name3']) после правильной инициализации. Подробнее см. https://docs.djangoproject.com/en/1.7/ref/models/lookups/.

20 голосов
/ 31 января 2014

В 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)

Поиск по индексу будет выполняться быстрее, чем запрос соответствия регулярному выражению.

12 голосов
/ 13 ноября 2017

Другой способ сделать это - использовать функции запросов django и аннотации

from django.db.models.functions import Lower
Record.objects.annotate(name_lower=Lower('name')).filter(name_lower__in=['two', 'one']
4 голосов
/ 22 июня 2012

Имейте в виду, что по крайней мере в 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, вы можете полностью игнорировать эту проблему.

3 голосов
/ 27 февраля 2012

Добавляя к сказанному Расмуджем, избегайте любого пользовательского ввода, например

import re
result = Name.objects.filter(name__iregex=r'(' + '|'.join([re.escape(n) for n in a]) + ')')
1 голос
/ 11 декабря 2018

Я расширяю идею Exgeny в два лайнера.

import functools
Name.objects.filter(functools.reduce(lambda acc,x: acc | Q(name_iexact=x)), names, Q()))
0 голосов
/ 22 мая 2018

Вот пример пользовательской модели пользователя 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...