python - site - Filtre la base de datos Django para el campo que contiene cualquier valor en una matriz
framework django para python (3)
Tengo un modelo django y un campo que representa el nombre completo de un usuario. Mi cliente quiere que configure un filtro para buscar un usuario en función de una serie de cadenas en las que todas tienen que ser sensibles a mayúsculas y minúsculas dentro del nombre completo.
Por ejemplo
Si un usuario full_name = "Keith, Thomson S."
Y tengo una lista [''keith'',''s'',''thomson'']
Quiero realizar el filtro equivalente de
Profile.objects.filter(full_name__icontains=''keith'',full_name__icontains=''s'',full_name__icontains=''thomson'')
El problema es que esta lista puede ser de tamaño dinámico, por lo que no sé cómo hacerlo.
¿Alguien tiene alguna idea?
Aún más corto usando las funciones de operator
and_
o or_
para combinar la lista de condiciones Q()
from operator import and_, or_
li = [''keith'', ''s'', ''thompson'']
Elementos que coinciden con todas las cadenas ( and_
)
Profile.objects.filter(reduce(and_, [Q(full_name__icontains=q) for q in li]))
Elementos que coinciden con cualquiera de las cadenas ( or_
)
Profile.objects.filter(reduce(or_, [Q(full_name__icontains=q) for q in li]))
La función Q()
implementa __or__()
y __and__()
y __and__()
para unir dos objetos Q()
, de modo que se pueden llamar usando las funciones del operator
correspondientes.
Haz sucesivas llamadas para filter
, así:
queryset = Profile.objects.all()
strings = [''keith'', ''s'', ''thompson'']
for string in strings:
queryset = queryset.filter(full_name__icontains=string)
Alternativamente, puedes &
juntos un montón de objetos Q
:
condition = Q(full_name__icontains=s[0])
for string in strings[1:]:
condition &= Q(full_name__icontains=string)
queryset = Profile.objects.filter(condition)
Una forma más críptica de escribir esto, evitando el bucle explícito:
import operator
# ...
condition = reduce(operator.and_, [Q(full_name__icontains=s) for s in strings])
queryset = Profile.objects.filter(condition)
algo en este sentido:
array = [''keith'', ''s'', ''thomson'']
regex = ''^.*(%s).*$'' % ''|''.join(array)
Profile.objects.filter(full_name__iregex=regex)
EDIT: esto es incorrecto, el OP quiere nombres que contengan todas las cadenas simultáneamente.