Django: usando los valores () y get_FOO_display ()?

Estoy tratando de mejorar un código existente que originalmente tomó 3 minutos para preparar una tabla de datos grande (luego devuelta por Ajax). El código antiguo iteró sobre un gran conjunto de consultas, reuniendo información de una variedad de objetos relacionados. Por lo que he leído, y desde la supervisión del registro de SQL, la iteración de los conjuntos de consultas es generalmente una mala idea, porque se ejecuta SQL para cada elemento. En su lugar, he estado usando valores para recostackr información en una sola instrucción SQL, y luego he estado iterando a través de eso. Usando esta técnica, he reducido el tiempo de ejecución a menos de 15 segundos (y todavía no he terminado). Sin embargo, como ya no uso los objetos del modelo, no puedo usar get_FOO_display () . ¿Hay alguna forma de usar esta funcionalidad al usar valores ()?

Simplificado, el original era:

for user in users: data.append(user.get_name_display()) # Appends 'Joe Smith' return data 

Y el nuevo código es:

 for user in users.values('name'): data.append(user['name']) # Appends 'JSmith001', which is incorrect return data 

Además, si hay alguna otra forma de preservar la creación de objetos modelo, pero solo se requiere una sola statement SQL en el backend, me encantaría saberlo. ¡Gracias!

En general, probablemente será mejor y más fácil usar una consulta basada en el Administrador que devuelva objetos del modelo. Parece que el problema con su enfoque original no es que estuviera iterando sobre su consulta (como dice @ahmoo, esto no es un problema de rendimiento), sino que dentro de su bucle de iteración estaba obteniendo objetos relacionados adicionales, que requieren uno o más Consultas adicionales para cada registro.

Hay varias formas de mejorar el rendimiento con consultas que aún devuelven instancias de modelo:

  • Parece que el más relevante es select_related() , que efectivamente hará una combinación de tablas en la consulta inicial para incluir datos de todos los objetos relacionados con claves externas.

  • Si eso no es suficiente, también puede agregar datos a las instancias de su modelo con extra() , lo que le permite incluir subconsultas en su SQL.

  • Y si todo esto falla, puede realizar consultas de SQL sin procesar utilizando el método .raw() en una instancia de Manager, que aún devolverá las instancias del modelo.

Básicamente, si puedes hacerlo en SQL de una manera que te dé una fila por instancia, hay una manera de hacerlo en Django y recuperar las instancias del modelo.

Sin embargo, para responder a su pregunta original, puede obtener el nombre para mostrar a través de la clase Field; es simplemente feo:

 def get_field_display(klass, field, value): f = klass._meta.get_field(field) return dict(f.flatchoices).get(value, value) # usage get_field_display(User, 'name', 'JSmith001') 

iterar sobre los conjuntos de consultas es generalmente una mala idea, porque se ejecuta SQL para cada elemento

Eso no es cierto. A continuación se toma de los documentos oficiales :

Un QuerySet es iterable y ejecuta su consulta de base de datos la primera vez que se itera sobre él.

Creo que el problema tiene que ver con la definición de los users partir de su código. ¿Qué le asignaste?