SQLAlchemy execute() 将 ResultProxy 作为元组返回,而不是 dict

Posted

技术标签:

【中文标题】SQLAlchemy execute() 将 ResultProxy 作为元组返回,而不是 dict【英文标题】:SQLAlchemy execute() return ResultProxy as Tuple, not dict 【发布时间】:2014-01-11 16:30:18 【问题描述】:

我有以下代码:

query = """
SELECT Coalesce((SELECT sp.param_value
                 FROM   sites_params sp
                 WHERE  sp.param_name = 'ci'
                        AND sp.site_id = s.id
                 ORDER  BY sp.id DESC
                 LIMIT  1), -1) AS ci
FROM   sites s
WHERE  s.deleted = 0
       AND s.id = 10 

"""

site = db_session.execute(query)
# print site 
# <sqlalchemy.engine.result.ResultProxy object at 0x033E63D0>

site = db_session.execute(query).fetchone()
print site  # (u'375')
print list(site) # [u'375']

为什么 SQLAlchemy 为这个查询返回元组,而不是字典?我想使用以下样式来访问查询结果:

print site.ci
# u'375'

【问题讨论】:

* confused * 您选择了"sp.param_value",但希望结果代理有一个名为"ci" 的成员?你可以使用像字典一样的结果代理,但你会使用像print site['param_value'] resultproxy 返回元组,我想要,那就是 resultproxy 返回字典 site['ci']site.ci 我同意@Gryphius。你可以这样试试print site['ci'] @Gryphius,@Syed Habib M,它不起作用! ResultProxy 返回元组,而不是 dict,而不是其他人!!! (u'375') 你试过了吗?你确定 Coalesce 表中有像“ci”这样的列名吗? 【参考方案1】:

这是一个老问题,但今天仍然很重要。让 SQL Alchemy 返回字典非常有用,尤其是在使用返回 JSON 的基于 RESTful 的 API 时。

这是我在 Python 3 中使用 db_session 的方法:

resultproxy = db_session.execute(query)

d, a = , []
for rowproxy in resultproxy:
    # rowproxy.items() returns an array like [(key0, value0), (key1, value1)]
    for column, value in rowproxy.items():
        # build up the dictionary
        d = **d, **column: value
    a.append(d)

最终结果是数组a 现在包含您的字典格式的查询结果。

至于这在 SQL Alchemy 中是如何工作的:

db_session.execute(query) 返回一个ResultProxy 对象 ResultProxy 对象由 RowProxy 对象组成 RowProxy 对象有一个 .items() 方法,该方法返回行中所有项目的键、值元组,可以在 for 操作中将其解包为 key, value

这里有一个单行替代方案:

[column: value for column, value in rowproxy.items() for rowproxy in resultproxy]

来自文档:

class sqlalchemy.engine.RowProxy(parent, row, processor, keymap)

来自单个游标行的代理值。

主要遵循“有序字典”行为,将结果值映射到基于字符串的列名、结果在行中的整数位置,以及可以映射到生成此结果集的原始 Column 的 Column 实例(对应于构造的 SQL 表达式的结果)。

has_key(key) 如果此 RowProxy 包含给定的键,则返回 True。

项目() 返回一个元组列表,每个元组包含一个键/值对。

键() 将键列表作为此 RowProxy 表示的字符串返回。

链接:http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

【讨论】:

我相信您的意思是将session.execute() 的结果分配给resultproxy,如下所示:resultproxy = db_session.execute(query) 这似乎对我有用,打字更少[dict(row) for row in resultproxy]【参考方案2】:

您查看过ResultProxy 文档吗? 它准确地描述了@Gryphius 和@Syed Habib M 的建议,即使用site['ci']

ResultProxy 并没有像您声称的那样“返回一个元组”——它(毫不奇怪)是一个代理,其行为(例如打印)类似于一个元组,但也支持类似字典的访问:

来自文档:

可以通过它们的整数位置访问各个列, 不区分大小写的列名,或通过 schema.Column 对象。例如:

row = fetchone()

col1 = row[0] # 通过整数位置访问

col2 = row['col2'] # 通过名称访问

col3 = row[mytable.c.mycol] # 通过 Column 对象访问。

【讨论】:

不适用于 sqlachemy 1.1。 ResultProxy 元素只是元组。唯一的方法似乎是访问 result.keys() 并用它构建你自己的字典。 @tothemario (当前)版本 1.2.x 的文档仍然包含我从上面复制和粘贴的 sn-p。所以看起来 ResultProxy 仍然不仅仅是一个元组。【参考方案3】:

我构建了一个简单的类,在我们的流程中像数据库接口一样工作。就是这样:

from sqlalchemy import create_engine
class DBConnection:
    def __init__(self, db_instance):
        self.db_engine = create_engine('your_database_uri_string')
        self.db_engine.connect()

    def read(self, statement):
        """Executes a read query and returns a list of dicts, whose keys are column names."""
        data = self.db_engine.execute(statement).fetchall()
        results = []

        if len(data)==0:
            return results

        # results from sqlalchemy are returned as a list of tuples; this procedure converts it into a list of dicts
        for row_number, row in enumerate(data):
            results.append()
            for column_number, value in enumerate(row):
                results[row_number][row.keys()[column_number]] = value

        return results        

【讨论】:

【参考方案4】:

您可以使用dict(site) 轻松地将每个结果行转换为字典。 如果存在ci 列,那么site['ci'] 将可用。

为了拥有site.ci(根据https://***.com/a/22084672/487460):

from collections import namedtuple
Site = namedtuple('Site', site.keys())
record = Site(*site)

【讨论】:

【参考方案5】:

这可能有助于解决 OP 问题。我认为他遇到的问题是行对象仅包含列值,而不包含列名本身,就像 ORM 查询的情况一样,其中结果具有 dict 属性,其中包含键和值.

python sqlalchemy get column names dynamically?

【讨论】:

【参考方案6】:

我发现的最简单的方法是使用 list comprehension 并在每个 RowProxy 上调用 dict() 函数

site = db_session.execute(query)
result = [dict(row) for row in site]

【讨论】:

【参考方案7】:

此方法使用列表推导,它接收一个 sql alchemy 行集对象并返回与字典列表相同的项目:

class ResultHelper():

@classmethod
def resultproxy_to_list(cls, sql_alchemy_rowset):        
        return [tuple[0]: tuple[1] for tuple in rowproxy.items() 
                                    for rowproxy in sql_alchemy_rowset]

【讨论】:

【参考方案8】:

当您调用db.execute(sql).fetchall() 时,您可以轻松使用以下函数将返回数据解析为字典:

def query_to_dict(ret):
    if ret is not None:
        return [key: value for key, value in row.items() for row in ret if row is not None]
    else:
        return []

【讨论】:

以上是关于SQLAlchemy execute() 将 ResultProxy 作为元组返回,而不是 dict的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy:execute() 得到了一个意外的关键字参数

SQLAlchemy engine.execute() 使与数据库的连接处于睡眠状态

使用 Pandas to_sql 时获取 sqlalchemy.exc.InternalError 异常值为 'cursor.execute(statement, parameters)'

无法在 ETL 过程中使用 Pandas 和 SQLAlchemy 将列名从 CSV 更改为 SQL Server DB

SQLAlchemy:防止自动关闭

sqlalchemy 执行原生sql语句