python - 类型错误 : 'dict' object does not support indexing thrown on second instance of this query

标签 python flask sqlalchemy flask-sqlalchemy psycopg

因此,我正在使用以下代码基于 Flask 中的用户输入构建查询:

    if empty_indic_form.validate_on_submit():
    query='select name, year, value, display_name from literal inner join ent on ent_id=ent.id where display_name in ('
    for i in indic_form.indicators.data:
        query=query+'\''+i+'\','
    query=query[:-1]+') '
    query=query+'and name in ('
    for c in order_c:
        query=query+c+','
    query=query[:-1]+')'
    data_return=db.engine.execute(query).fetchall()

我已经确认查询看起来像它应该的那样,甚至有一个早期的 session ,它返回了我期望的 rowproxy 对象列表。但是现在无论我做什么我都会收到这个错误!

我已将查询设置为模板中的一个变量,以便打印出来,这是我得到的结果:

select name, year, value, display_name from literal inner join ent on ent_id=ent.id where display_name in ('Energy savings of primary energy (TJ)','Adolescent birth rate (women aged 15-19 years)','Net migration rate','Transmission and distribution losses (%)') and name in ('Burkina Faso', 'Ghana', 'Saudi Arabia', 'Pakistan')

我直接在我的 Postgres 数据库上运行它,结果非常好。

在错误转储中,我注意到 data_return=db.engine.execute(query).fetchall() 行正在构建一个空字典作为参数,这当然会引发该错误结束。我可以强制它不这样做吗?查询对象看起来像上面那样,现在有什么问题吗?我是否应该在刷新页面或转到主页时终止数据库 session ?

最佳答案

您方法中的根本错误是使用字符串连接来构建 SQL 查询。如果 indic_form.indicators.dataorder_c 是用户提供的数据,例如来自 HTTP 请求,您可能已经为 SQL injection 打开了自己的大门。 .错误

TypeError: 'dict' object does not support indexing

是此连接的结果:您的查询字符串包含流氓 "%",它是 psycopg 的占位符语法的一部分– 通常与 SQLAlchemy 一起使用的 DB-API 与 Postgresql 对话。这正是不应进行手动连接的原因。正确逃离可能很困难。

将值列表传递给 IN 运算符是使用 tuples adaptation 完成的在 Psycopg2 中。在 SQLAlchemy 中,您将使用 in_列运算符,或 expanding bind param那是introduced in version 1.2 .

不幸的是,在您的特定情况下,SQLAlchemy 包装引擎有一个陷阱:因为您的所有参数都是元组,SQLAlchemy 引擎认为您正试图将一个可迭代的参数元组作为 multiparams 传递给它。并自动使用 executemany()。您可以使用 text() 解决此问题构造,它允许 DB-API 不可知的绑定(bind)参数语法和字典作为参数容器:

from sqlalchemy import text

...

if empty_indic_form.validate_on_submit():
    # Note that the placeholders shouldn't have enclosing parentheses
    query = """SELECT name, year, value, display_name
               FROM literal
               INNER JOIN ent ON ent_id = ent.id
               WHERE display_name IN :display_name
                 AND name IN :name"""

    data_return = db.engine.execute(
        text(query), {'display_name': tuple(indic_form.indicators.data),
                      'name': tuple(order_c)}).fetchall()

回顾一下:永远不要使用字符串连接或手动格式化来构建 SQL 查询。始终使用占位符/绑定(bind)参数。

关于python - 类型错误 : 'dict' object does not support indexing thrown on second instance of this query,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38090730/

相关文章:

python - 通过 IPython 使用 Jython : is readline still an issue?

python - 如何从 python 中编译的正则表达式模式中获取模式字符串?

Docker 正在运行,但我无法访问 localhost - Flask 应用程序

python - 如何处理 Flask 上的静态/媒体文件权限?

postgresql - 如何在 Flask session 中设置 PostgreSQL 数据库的模式名称

python - SQLAlchemy 从 create() 打印原始 SQL

connection - sqlalchemy中MapperExtension的 `connection`参数是什么?

python - Flask 应用程序中的数据未提交到数据库

sqlalchemy - 使用 python-asyncio 数据库时如何获取最后插入 ID

python - num 求和不正确