У меня есть список имен, которые я хочу совместить без учета регистра, есть ли способ сделать это, не используя цикл, как показано ниже?
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])
Unfortunatley, нет поиска __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 их правильно.
НОВОСТИ: В Djano 1.7 можно создавать собственные поисковые запросы, поэтому вы можете фактически использовать filter(name__iin=['name1', 'name2', 'name3'])
после правильной инициализации. Подробнее см. https://docs.djangoproject.com/en/1.7/ref/models/lookups/.
В Postgresql вы можете попробовать создать индекс без учета регистра, как описано здесь:
fooobar.com/questions/222395/...
Затем запустите запрос:
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 и аннотаций
from django.db.models.functions import Lower
Record.objects.annotate(name_lower=Lower('name')).filter(name_lower__in=['two', 'one']
Имейте в виду, что, по крайней мере, в 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, вы можете вообще игнорировать проблему.
Добавляя к тому, что сказал Rasmuj, избегайте любого пользовательского ввода таким образом
import re
result = Name.objects.filter(name__iregex=r'(' + '|'.join([re.escape(n) for n in a]) + ')')
Вот пример пользовательского classmethod
модели classmethod
для фильтрации пользователей по электронной почте без 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)
Я расширяю идею Exgeny в два лайнера.
import functools
Name.objects.filter(functools.reduce(lambda acc,x: acc | Q(name_iexact=x)), names, Q()))