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。