2011-01-27 16 views
27

tengo un capricho con filtrado queryset Django (?):Django objects.filter() values_list() versus lista de pitón comprensión de consulta __in

ipdb> MagazineIssue.objects.filter(id__in=l_magazines.values_list('id')) 
Out[0]: [] 

o

ipdb> MagazineIssue.objects.filter(id__in=[l_magazine.id for l_magazine in l_magazines]) 
Out[0]: [<MagazineIssue: Architecture Australia, Jan 1995 (#1)>] 

y

ipdb> l_magazines.values_list('id') 
Out[0]: [(1,)] 
ipdb> [l_magazine.id for l_magazine in l_magazines] 
Out[0]: [1] 

Entonces, ¿cómo usar values_list()? (para producir):

[1] 

o es la comprensión de la lista de python el 'camino a seguir'?

Respuesta

56

Probar l_magazines.values_list('id', flat=True). Eso devuelve una lista de identificadores en lugar de una lista de tuplas de identificadores individuales.

+5

¿Hay una diferencia de rendimiento? – Marcin

+3

Enorme. values_list es más rápido. flat = true lo hace aún más rápido porque Python no necesita crear una instancia de todos los objetos en la lista, solo se devuelven los valores de la base de datos. –

+1

para aclarar, es más rápido porque Django reconoce que estamos utilizando un conjunto de interrogación como argumento para un conjunto de consulta, por lo que los combina en una sola consulta: ¡no evalúa primero el conjunto de consultas 'values_list' en una lista! – Anentropic

2

Una cosa a tener en cuenta es que hay una diferencia en el comportamiento de los valores/values_list de una lista de comprensión:

  • valores/values_list dará el valor real almacenado en el campo, es decir, sólo el id (no el objeto completo)
  • si el valor es una clave externa, y tiene las relaciones adecuadas establecidas en su modelo, la comprensión de la lista le proporcionará el objeto al que hace referencia la clave externa.

Elegir el incorrecto provocará resultados innecesarios en la base de datos, o un descuido innecesario, dependiendo de lo que esté intentando hacer.