tutorial query español python orm sqlalchemy

python - query - sqlalchemy sqlite



SQL Alchemy ORM devuelve una sola columna, cómo evitar el procesamiento posterior común (5)

Estoy usando el ORM de SQL Alchemy y me parece que cuando devuelvo una sola columna obtengo los resultados así:

[(result,), (result_2,)] # etc...

Con un conjunto como este me parece que tengo que hacer esto a menudo:

results = [r[0] for r in results] # So that I just have a list of result values

Esto no es tan "malo" porque mis conjuntos de resultados son generalmente pequeños, pero si no lo fueran, esto podría agregar una sobrecarga significativa. Lo más importante es que siento que desordena la fuente, y perder este paso es un error bastante común que me encuentro.

¿Hay alguna forma de evitar este paso extra?

Un comentario relacionado: este comportamiento del orm parece inconveniente en este caso, pero en otro caso donde mi conjunto de resultados era, [(id, value)] termina así:

[(result_1_id, result_1_val), (result_2_id, result_2_val)]

Entonces puedo hacer:

results = dict(results) # so I have a map of id to value

Éste tiene la ventaja de tener sentido como un paso útil después de devolver los resultados.

¿Es esto realmente un problema o simplemente estoy siendo quisquilloso y el procesamiento posterior después de obtener el conjunto de resultados tiene sentido para ambos casos? Estoy seguro de que podemos pensar en algunas otras operaciones comunes de procesamiento posterior para hacer que el conjunto de resultados sea más útil en el código de la aplicación. ¿Existe un alto rendimiento y soluciones convenientes en todos los ámbitos o es inevitable el procesamiento posterior, y simplemente se requiere para diferentes usos de aplicaciones?

Cuando mi aplicación puede aprovechar los objetos devueltos por el ORM de SQL Alchemy parece extremadamente útil, pero en los casos en que no puedo o no puedo, no tanto. ¿Es este solo un problema común de los ORM en general? ¿Será mejor que no use la capa ORM en casos como este?

Supongo que debería mostrar un ejemplo de las consultas de orm reales de las que estoy hablando:

session.query(OrmObj.column_name).all()

o

session.query(OrmObj.id_column_name, OrmObj.value_column_name).all()

Por supuesto, en una consulta real normalmente habría algunos filtros, etc.


El código postal de Python combinado con el * operador de expansión en línea es una solución bastante útil para esto:

>>> results = [(''result'',), (''result_2'',), (''result_3'',)] >>> zip(*results) [(''result'', ''result_2'', ''result_3'')]

Entonces solo tiene que [0] indexar una vez. Para una lista tan corta, tu comprensión es más rápida:

>>> timeit(''result = zip(*[("result",), ("result_2",), ("result_3",)])'', number=10000) 0.010490894317626953 >>> timeit(''result = [ result[0] for result in [("result",), ("result_2",), ("result_3",)] ]'', number=10000) 0.0028390884399414062

Sin embargo, para las listas más largas, zip debe ser más rápido:

>>> timeit(''result = zip(*[(1,)]*100)'', number=10000) 0.049577951431274414 >>> timeit(''result = [ result[0] for result in [(1,)]*100 ]'', number=10000) 0.11178708076477051

Depende de usted determinar cuál es mejor para su situación.


Una forma de disminuir el desorden en la fuente es repetir de esta manera:

results = [r for (r, ) in results]

Aunque esta solución tiene un carácter más largo que el operador [] , creo que es más fácil para los ojos.

Para aún menos desorden, elimine el paréntesis. Esto hace que sea más difícil cuando lee el código, para notar que en realidad está manejando tuplas:

results = [r for r, in results]


Luché con esto también hasta que me di cuenta de que es como cualquier otra consulta:

for result in results: print result.column_name


Mi solución se ve así;)

def column(self): for column, *_ in Model.query.with_entities(Model.column).all(): yield column

NOTA: solo py3.


Encontré el siguiente más legible , también incluye la respuesta para el dict (en Python 2.7):

d = {id_: name for id_, name in session.query(Customer.id, Customer.name).all()} l = [r.id for r in session.query(Customer).all()]

Para el valor único, tomando prestado de otra respuesta:

l = [name for (name, ) in session.query(Customer.name).all()]

Compare con la solución zip incorporada, adaptada a la lista:

l = list(zip(*session.query(Customer.id).all())[0])

que en mi tiempo proporciona solo un 4% de mejoras de velocidad.