如何从SQLAlchemy表达式获取原始的、编译的SQL查询?

2024-04-26 21:17:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个SQLAlchemy查询对象,希望获取已编译的SQL语句的文本,并绑定它的所有参数(例如,没有%s或等待语句编译器或MySQLdb方言引擎绑定的其他变量等)。

对查询调用str()会显示如下内容:

SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC

我试过在查询中查找参数。参数是空的。我用this example of the ^{} decorator编写了自己的编译器,但即使是那里的语句在我需要数据的地方也有%s

我不太清楚我的参数是什么时候混合在一起创建查询的;当检查查询对象时,它们总是一个空字典(尽管查询执行得很好,当您打开echo日志时,引擎会打印出来)。

我开始得到这样的消息:SQLAlchemy不想让我知道底层查询,因为它打破了expression API接口的一般性质所有不同的dbapi。我不介意查询在我发现它是什么之前被执行;我只是想知道!


Tags: 对象引擎文本内容addedsql参数date
3条回答

这应该适用于Sqlalchemy>;=0.6

from sqlalchemy.sql import compiler

from psycopg2.extensions import adapt as sqlescape
# or use the appropiate escape function from your db driver

def compile_query(query):
    dialect = query.session.bind.dialect
    statement = query.statement
    comp = compiler.SQLCompiler(dialect, statement)
    comp.compile()
    enc = dialect.encoding
    params = {}
    for k,v in comp.params.iteritems():
        if isinstance(v, unicode):
            v = v.encode(enc)
        params[k] = sqlescape(v)
    return (comp.string.encode(enc) % params).decode(enc)

documentation使用literal_binds打印查询q,包括参数:

print(q.statement.compile(compile_kwargs={"literal_binds": True}))

the above approach has the caveats that it is only supported for basic types, such as ints and strings, and furthermore if a bindparam() without a pre-set value is used directly, it won’t be able to stringify that either.

文档还发出以下警告:

Never use this technique with string content received from untrusted input, such as from web forms or other user-input applications. SQLAlchemy’s facilities to coerce Python values into direct SQL string values are not secure against untrusted input and do not validate the type of data being passed. Always use bound parameters when programmatically invoking non-DDL SQL statements against a relational database.

This博客提供了更新的答案。

引用博客文章,这是我的建议和工作。

>>> from sqlalchemy.dialects import postgresql
>>> print str(q.statement.compile(dialect=postgresql.dialect()))

其中q定义为:

>>> q = DBSession.query(model.Name).distinct(model.Name.value) \
             .order_by(model.Name.value)

或者只是任何类型的session.query()。

感谢尼古拉斯·卡杜的回答!我希望它能帮助到这里来找东西的人。

相关问题 更多 >