为什么在 psycopg2 中占位符比文字更受欢迎?

问题描述 投票:0回答:1

来自 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)))

这样不是更好吗?

python sql psycopg2
1个回答
0
投票

我知道这已经过时了一段时间,但我只是偶然发现了这个问题,并想为所有后来到达这里的人提供答案:

  • 一般来说,sql.Literal 和具有插入值的 sql.Placeholder 的行为类似。我不想说完全相同,因为至少对于 psycopg3 来说,带有占位符的查询和填充这些占位符的值被单独发送到服务器,然后在那里组合 - 所以在执行中存在真正的差异 -尽管大多数时候它不会产生很大的影响。
  • 真正的区别在于职责的分配:cursor.execute() 将查询和值作为参数,并且不需要内联查询,甚至不需要与执行命令位于同一文档中,这会非常方便。在我们不断发展的项目中,我们转向基于特殊 sql-generator 模块中的一些参数返回 sql.Composition 对象的函数,然后将这些参数导入到执行查询的文档中。这使得应用程序代码和 sql 代码都更容易阅读,因为它减少了缩进,甚至将 sql 从应用程序开发人员中抽象出来(至少有一点 - 她仍然需要知道查询需要哪些参数,但这可以在文档字符串中维护)。

示例:

  • sql.py
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")
  • 应用程序.py
from .sql import build_big_cat_getter_query
...
big cats = cur.execute(
    build_big_cat_getter_query(),
    {'min_cat_size': 3.1415}
)

当然,这是一个相当简单的示例,但在我们的项目中,有多个构建器接受描述所需过滤器结构或所需占位符数量的参数(例如,对于数组)。应用程序开发人员不需要知道查询是如何形成的,只需要知道占位符要求 - 以及它的可重用性并且可以与executemany一起使用。

我希望它对某人有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.