SQL Alchemy ORM返回单个列,如何避免常见的后期处理
我正在使用SQL Alchemy的ORM,我发现当我返回一列时,我得到如下结果:
[(result,), (result_2,)] # etc...
有了这样一个集合,我发现我必须经常这样做:
results = [r[0] for r in results] # So that I just have a list of result values
这不是“坏”,因为我的结果集通常很小,但如果它们不是这样会增加大量的开销。 最大的问题是我觉得混乱的源头,错过了这一步是我碰到一个相当常见的错误。
有没有办法避免这个额外的步骤?
一个相关的因素:在这种情况下,orm的这种行为似乎很不方便,但另一种情况是我的结果集是[(id,value)],结果如下:
[(result_1_id, result_1_val), (result_2_id, result_2_val)]
然后我可以做:
results = dict(results) # so I have a map of id to value
在返回结果之后,这个作为一个有用的步骤是有意义的。
这真的是一个问题,或者我只是一个挑剔的和后处理得到的结果集是有道理的两种情况? 我确定我们可以考虑一些其他常见的后处理操作,以使结果集在应用程序代码中更加可用。 是否有全面的高性能和便捷的解决scheme,或者后期处理是不可避免的,只是需要不同的应用程序?
当我的应用程序实际上可以利用由SQL Alchemy的ORM返回的对象时,它看起来非常有用,但是在我不能或不可以的情况下,并不是那么多。 这只是ORM的普遍问题吗? 在这种情况下,我最好不要使用ORM层?
我想我应该展示一个我正在谈论的实际orm查询的例子:
session.query(OrmObj.column_name).all()
要么
session.query(OrmObj.id_column_name, OrmObj.value_column_name).all()
当然,在一个真正的查询中,通常会有一些filter等。
Python的zip与* inline扩展运算符相结合,是一个非常方便的解决scheme:
>>> results = [('result',), ('result_2',), ('result_3',)] >>> zip(*results) [('result', 'result_2', 'result_3')]
那么你只需要[0]索引一次。 对于这样一个简短的列表,你的理解速度会更快:
>>> 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
但是对于更长的列表,zip应该更快:
>>> timeit('result = zip(*[(1,)]*100)', number=10000) 0.049577951431274414 >>> timeit('result = [ result[0] for result in [(1,)]*100 ]', number=10000) 0.11178708076477051
所以这是由你来决定哪个更适合你的情况。
减less源代码中混乱的一种方法是像这样迭代:
results = [r for (r, ) in results]
虽然这个解决scheme比使用[]
运算符长一个字符,但是我认为它更容易。
为了减less混乱,请删除括号。 这使得阅读代码时更难,注意到你实际上正在处理元组,但是:
results = [r for r, in results]
我也一直在努力,直到我意识到它就像任何其他查询:
for result in results: print result.column_name
我发现下面更具可读性 ,还包括dict的答案(在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()]
对于单一的价值,借用另一个答案:
l = [name for (name, ) in session.query(Customer.name).all()]
与内置的zip
解决scheme相比,适应于以下列表:
l = list(zip(*session.query(Customer.id).all())[0])
这在我的时间只提供了大约4%的速度改善。
我的解决scheme是这样的;)
def column(self): for column, *_ in Model.query.with_entities(Model.column).all(): yield column
注意:只有py3。