2010-04-19 10 views
23

Ho una lista di nomi che voglio abbinare case insensitive, c'è un modo per farlo senza l'utilizzo di un ciclo come qui di seguito?Django di query case-insensitive partita

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

risposta

27

Sfortunatamente, non ci sono senza__iin campo di ricerca. Ma c'è un iregex che potrebbe essere utile, in questo modo:

result = Name.objects.filter(name__iregex=r'(name1|name2|name3)') 

o anche:

a = ['name1', 'name2', 'name3'] 
result = Name.objects.filter(name__iregex=r'(' + '|'.join(a) + ')') 

Si noti che se un possono contenere caratteri che sono speciali in una regex, è necessario escape in modo corretto .

NOTIZIE: In Djano 1.7 è possibile creare le proprie ricerche, quindi è possibile utilizzare effettivamente filter(name__iin=['name1', 'name2', 'name3']) dopo l'inizializzazione corretta. Vedi https://docs.djangoproject.com/en/1.7/ref/models/lookups/ per i dettagli.

+2

Postgres supporta indici case-insensitive, quindi per questo caso può essere più veloce per eseguire query separate "iexact" per ogni voce di partite iregex. Nel post-back di django la ricerca "iexact" utilizza una trasformazione UPPER(), quindi con un indice personalizzato su UPPER() per quella riga è possibile ottenere un aumento della velocità. – Evgeny

+5

Vorrei che implementassero __iin – JREAM

+0

@Evgeny Vorrei poter aggiungere una risposta o darci un collegamento. Grazie! –

3

Aggiunta su quello che ha detto Rasmuj, sfuggire ad ogni input degli utenti in questo modo

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

Tenete presente che, almeno in MySQL è necessario impostare utf8_bin fascicolazione nelle tabelle per rendere effettivamente maiuscole e minuscole. Altrimenti sono case preserving ma case insensitive. Per esempio.

>>> 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>] 

Quindi, se la portabilità non è cruciale e si utilizza MySQL si può scegliere di ignorare la questione del tutto.

15

in PostgreSQL si potrebbe provare a creare un indice di insensibile caso, come descritto qui:

https://stackoverflow.com/a/4124225/110274

Poi esegue una query:

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) 

ricerca Indice sarà correre più veloce di query regex corrispondente.

+0

Grazie! ho avuto l'idea –

+1

Attenzione con questo codice! Se il nome della variabile è vuoto, il file .filter restituirà tutti gli oggetti di quel modello! – Benjamin

1

Un altro modo per questo utilizzando django query functions e annotazione

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