来自 psycopg2 文档,
class psycopg2.sql.Literal(wrapped) ...通常您会希望在查询中包含占位符并将值作为execute() 参数传递。但是,如果您确实需要在查询中包含文字值,则可以使用此对象。
Literal
难道不会带来更干净、更安全、几乎不会出错的实施吗?例如,假设查询包含 %
。您需要确保所有 %
都被另一个 %
转义。
>>> cur.execute("SELECT (%s % 2) = 0 AS even", (10,)) # Wrong
>>> cur.execute("SELECT (%s %% 2) = 0 AS even", (10,)) # Correct
然后是序列参数错误
>>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # Wrong
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # Wrong
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # Correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # Correct
以及单引号错误
>>> cur.execute("INSERT INTO numbers VALUES ('%s')", (10,)) # Wrong
>>> cur.execute("INSERT INTO numbers VALUES (%s)", (10,)) # Correct
还有其他人。
有了
Literal
你就可以使用
>>> cur.execute(sql.SQL("SELECT ({} % 2) = 0 AS even").format(sql.Literal(10)))
这样不是更好吗?
我知道这已经过时了一段时间,但我只是偶然发现了这个问题,并想为所有后来到达这里的人提供答案:
示例:
def build_big_cat_getter_query() -> sql.Composed:
return sql.SQL(
"SELECT * FROM cats WHERE size > {min_cat_size}"
).format(min_cat_size=sql.Placeholder("min_cat_size")
from .sql import build_big_cat_getter_query
...
big cats = cur.execute(
build_big_cat_getter_query(),
{'min_cat_size': 3.1415}
)
当然,这是一个相当简单的示例,但在我们的项目中,有多个构建器接受描述所需过滤器结构或所需占位符数量的参数(例如,对于数组)。应用程序开发人员不需要知道查询是如何形成的,只需要知道占位符要求 - 以及它的可重用性并且可以与executemany一起使用。
我希望它对某人有帮助。