SQLAlchemy 返回元组而不是字典
我把SQLAlchemy更新到了0.6版本,但这导致一切都出问题了。我发现它现在返回的是元组,而不是字典了。这里有一个示例查询:
query = session.query(User.id, User.username, User.email).filter(and_(User.id == id, User.username == username)).limit(1)
result = session.execute(query).fetchone()
这段代码在0.5版本时是返回一个字典的。
我想问的是,怎么才能让它返回一个字典呢?
4 个回答
你确定它不是一个 ResultProxy 吗?这个东西在你打印的时候看起来像一个元组。很多在ORM(对象关系映射)里的对象,其实并不是它们的 __str__
函数所显示的样子。
session.execute 这个方法从来没有返回过字典,它返回的是一个 RowProxy 对象。这个对象可以像字典一样用来索引,也就是说你可以用数字键来按位置查找,或者用字符串键根据标签查找,甚至可以用列对象来查找该列的值。这里的问题是,session.execute(query)
并没有按照你想的那样工作。它把 Query 对象转换成一个 Select 语句,执行这个语句,然后直接返回结果。结果集并不知道 ORM 层的特性。在 0.5 和 0.6 版本之间的变化是,ORM 现在用不同的算法来给查询中的列命名,它会在标签前面加上表名。所以之前 row['id']
能用,现在你需要用 row['users_id']
。不过在这两种情况下,row[User.__table__.columns['id']]
都能正常工作。
要执行 ORM 查询,你其实应该使用 .all()
、.first()
和 .one()
这些方法,或者通过迭代来获取结果,或者使用数字索引。查询返回的是命名元组对象。如果你想要一个字典,可以把元组和它的键结合起来:
row = session.query(User.id, User.username, User.email)\
.filter(and_(User.id == id, User.username == username)).first()
print("id=%s username=%s email=%s" % row) # positional
print(row.id, row.username) # by label
print(dict(zip(row.keys(), row))) # as a dict
这个方法应该可以用:
dict(zip(['id','username','email'],result))
(如果你用的是Python 3.x的话,也可以用字典推导式)。
另外,你不需要在session.query
对象上调用session.execute
。你应该直接使用它的.one()
方法。这样也就不需要在查询的最后加上.limit(1)
了。