如何明确引用字符串值(Python DB API/Psycopg2)

29 投票
10 回答
37669 浏览
提问于 2025-04-11 18:36

出于某些原因,我想要明确地给一个字符串加上引号(这个字符串会成为构建的SQL查询的一部分),而不是等着cursor.execute方法在它的第二个参数内容上自动加引号。

我所说的“自动加引号”是指:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;"
cursor.execute( query, (value,) ) # value will be correctly quoted

我更希望能像这样:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    READY_TO_USE_QUOTING_FUNCTION(value)
cursor.execute( query ) # value will be correctly quoted, too

在Python的数据库API规范中,是否有这样的低级READY_TO_USE_QUOTING_FUNCTION?我在PEP 249文档中找不到这样的功能。如果没有,Psycopg2有没有提供这样的函数?如果也没有,Django有没有提供这样的函数?我希望不必自己去写这样的函数...

10 个回答

2

你应该尽量避免自己去处理引号。正如大家所提到的,这不仅会依赖于具体的数据库,而且引号处理不当是导致SQL注入漏洞的根源。

如果你不想把查询和参数分开传递,那就可以把参数放在一个列表里一起传递:

def make_my_query():
    # ...
    return sql, (value1, value2)

def do_it():
    query = make_my_query()
    cursor.execute(*query)

(我可能写错了cursor.execute的语法)这里的重点是,虽然cursor.execute需要多个参数,但这并不意味着你必须把它们一个个单独处理。你可以把它们作为一个列表来处理。

17

我想你是在找 mogrify 这个函数。

下面是一个例子:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"
34

好吧,我出于好奇去查看了psycopg2的源代码。结果发现我只需要看看示例文件夹就够了 :)

没错,这个内容是针对psycopg2的。基本上,如果你只是想给一个字符串加上引号,你可以这样做:

from psycopg2.extensions import adapt

print adapt("Hello World'; DROP DATABASE World;")

但你可能更想做的是编写并注册你自己的适配器;

在psycopg2的示例文件夹中,你会找到一个文件'myfirstrecipe.py',里面有一个如何以特殊方式转换和加引号的具体类型的例子。

如果你有想要处理的对象,你可以创建一个符合'IPsycopgSQLQuote'协议的适配器(可以查看myfirstrecipe.py示例的文档……其实这是我能找到的唯一相关参考),这个适配器会给你的对象加上引号,然后像这样注册它:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

另外,其他的示例也很有趣;特别是'dialtone.py''simple.py'

撰写回答