如何显式引用字符串值(Python DB API/Psycopg2)

如何显式引用字符串值(Python DB API/Psycopg2),python,sql,django,psycopg2,Python,Sql,Django,Psycopg2,出于某些原因,我希望对字符串值进行显式引用(成为构造的SQL查询的一部分),而不是等待cursor.execute方法对其第二个参数的内容执行隐式引用 我所说的“隐含报价”是指: 我更喜欢这样的: value = "Unsafe string" query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \ READY_TO_USE_QUOTING_FUNCTION(value) cursor.execute( que

出于某些原因,我希望对字符串值进行显式引用(成为构造的SQL查询的一部分),而不是等待
cursor.execute
方法对其第二个参数的内容执行隐式引用

我所说的“隐含报价”是指:

我更喜欢这样的:

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

PythonDB API规范所期望的低级别
是否准备好使用功能
(我在文档中找不到这样的功能)。如果没有,Psycopg2是否提供了这样的功能?如果没有,Django是否提供了这样的功能?我不希望自己编写这样的函数…

这将取决于数据库。例如,在MySQLdb的情况下,
连接
类有一个
文本
方法,该方法将值转换为正确的转义表示形式,以传递给MySQL(这就是
cursor.execute
使用的)


我想Postgres也有类似的功能,但我不认为在DB API 2.0规范中有转义值的功能。

这将依赖于数据库(iirc,mysql允许
\
作为转义字符,而oracle则希望引号加倍:
'my''quoted string'

如果我错了,有人会纠正我,但双重引用法是标准方法

其他数据库抽象库(sqlalchemy、cx_Oracle、sqlite等)的功能可能值得一看


我不得不问-为什么你想内联这些值而不是绑定它们?

你应该尽量避免自己引用。正如人们所指出的,它不仅是DB特有的,而且引用中的缺陷也是SQL注入错误的根源

若不想分别传递查询和值,请传递参数列表:

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

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

(我可能有cursor.execute的语法错误)这里的要点是,仅仅因为cursor.execute接受许多参数,并不意味着您必须单独处理它们。你可以把它们作为一个列表来处理。

好的,所以我很好奇,去看看psycopg2的来源。事实证明,我不必再深入示例文件夹:)

是的,这是psycopg2特有的。基本上,如果您只想引用字符串,您可以这样做:

from psycopg2.extensions import adapt

print adapt("Hello World'; DROP DATABASE World;")
但您可能想做的是编写并注册您自己的适配器

在psycopg2的examples文件夹中,您可以找到一个文件,其中有一个如何以特殊方式强制转换和引用特定类型的示例

如果你有你想做的事情的对象,你可以创建一个符合“IPsycopgSQLQuote”协议的适配器(参见myfirstrecipe.py示例的pydocs…实际上这是我能找到的唯一引用该名称)引用你的对象,然后像这样注册它:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

另外,其他例子也很有趣;特别是和。

如果您使用django,您可能希望使用自动适应当前配置的DBMS的报价功能:

from django.db import backend
my_quoted_variable = backend.DatabaseOperations().quote_name(myvar)

我认为你没有给出任何充分的理由来避免这样做。请按设计使用APi,不要试图让你的代码对下一个家伙来说不那么可读,更脆弱。

根据

getquoted
函数将
值作为带引号的转义字符串返回,因此您也可以转到:
“从某个表中选择*,其中某个字符字段=“+adapt(value).getquoted()


至少在MySQL中可以完成简单的引用工作。不过,我们真正需要的是cursor.format()函数,它的工作方式与cursor.execute()类似,只是它会返回结果查询,而不是执行它。有时,您还不希望执行查询-例如,您可能希望先将其记录下来,或者在继续执行之前将其打印出来进行调试。

我猜您正在寻找该函数

例如:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"
这是构建SQL语句的另一个好选项。使用示例(基于项目主页上的示例):


我有很多非常重要的查询,其中包含一些重复模式(例如,多个WHERE条件集)。我已经定义了一些类,它们封装了必要的数据和SQL生成代码。在处理复杂的查询生成时,我通常会传回一个参数化的查询字符串和单独的参数列表。我建议您研究一下SQLAlchemy的SQLBuilderAPI,即使您对ORM组件不感兴趣;这将允许您在保持灵活性的同时绑定值。类似于
db\u cur.execute('''UPDATE test\u table SET field_1=“%s”其中field_2=“%s”'%”(数据,条件))
注意
%s
''周围的三个单引号和双引号允许不必将整个sql保留在一行中您也可以将它们作为dict:cursor传递。执行(“某些sql%(aparam)s、%(另一个)s、%(aparam)s”,adict)尽管如此,这在所有情况下都不起作用;在执行多行插入和类似构造时,这是不可能实现的。无论您需要进行什么样的数据库调用结构,您都可以构建一个抽象来保存数据,直到使用它为止。想要抽象地构建查询并不是将您自己的引用拼凑在一起的借口。当然是这样,但在某个时候,您确实需要引用您的数据,无论您将数据隐藏在多少抽象层之下,并且executemany提供的机制无法支持SQL中所有值的使用。好的,所以可以这样做,例如sql='insert into x values'+','.join(“(%s,%s)”,)*len(values))等等,但我觉得这不是一个很好的解决方案。
quote\u name
用双引号括住结果字符串。PostgreSQL(8.2.5)不允许将其作为
from psycopg2.extensions import adapt

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

def db_quote(s):
  return "\"" + re.escape(s) + "\""
>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"
>>> from pypika import Order, Query
>>> Query.from_('customers').select('id', 'fname', 'lname', 'phone').orderby('id', order=Order.desc)
SELECT "id","fname","lname","phone" FROM "customers" ORDER BY "id" DESC