我使用SQLAlchemy连接到Python中的不同数据库,但没有使用ORM支持,因为有几个原因导致无法实现。
主要是我使用
之类的东西构建复杂的SQL查询sql += "AND fieldname = '%s'" % myvar
在我的情况下,不是SQL注入的问题,因为数据总是来自受信任的来源,但即使源是可信的,它也可能包含可能破坏查询的字符,如'
,%
或_
。
主要是,我需要逃避它们,我想知道是否有一个已经存在的可以重复使用的转义函数。
答案 0 :(得分:9)
你不应该尝试实现自己的转义,而应该使用SQLAlchemy的内置方法:
sql = 'select * from foo where fieldname = :name'
result = connection.execute(sql, name = myvar)
答案 1 :(得分:2)
扩展@edd 的答案,其作用有限。
@edd 提供:
import sqlalchemy
engine = sqlalchemy.create_engine(...)
sqlalchemy.String('').literal_processor(dialect=engine.dialect)(value="untrusted value")
如果您的“不受信任的值”是您要执行的查询,这将最终得到一个包含单引号字符串的双引号字符串,如果不去掉引号,您将无法直接执行该字符串,即 {{1} }.
您可以使用 "'SELECT ...'"
来做同样的事情,但结果不会有额外的内引号,因为它旨在创建一个像 sqlalchemy.Integer().literal_processor
这样的整数而不是像 {{1} 这样的字符串}}。所以你的结果只会被引用一次:5
。
我发现这个整数方法有点粗略 - 阅读我代码的人会知道我为什么要这样做吗?至少对于 psycopg2 来说,有一个更直接、更清晰的方法。
如果您的底层驱动程序是 psycopg2,您可以使用 sqlalchemy 深入驱动程序,获取光标,然后使用 psycopg2 的 '5'
绑定和转义您的查询
"SELECT ..."
我知道如何从这个答案中抓取光标:SQLAlchemy, Psycopg2 and Postgresql COPY
并从这个答案中得到mogrify:psycopg2 equivalent of mysqldb.escape_string?
我的用例是构建一个查询,然后将其包装在括号中并使用 cursor.mogrify
之类的别名,以便将其传递给 PySpark JDBC from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
cursor = session.connection().connection.cursor()
processed_query = cursor.mogrify([mogrify args, see docs]).decode("UTF-8")
。当 SQLAlchemy 构建查询时,它会最小化括号,因此我只能得到 (SELECT ...) AS temp_some_table
。我使用上面的方法来获得我需要的东西:
read
答案 2 :(得分:1)
编译并完成其他贡献者的答案。
写直接SQL字符串通常是一个糟糕的解决方案,因为每个数据库系统都支持自己的SQL方言,因此SQL字符串通常不能跨数据库移植。
为了使用户免除此问题,SQLAlchemy邀请您以更加面向对象的方式在更高级别上编写SQL查询。它被称为SQL Expression语言,并在此处进行记录: https://docs.sqlalchemy.org/en/13/core/tutorial.html
基本上,您可以使用Python构建描述您要执行的操作的表达式,SQLAlchemy会使用适合您所用数据库的方言为您生成相应的SQL字符串。
由于您熟悉SQL,因此您可以在数小时内学会这种“迷你语言”(我很犹豫在此处输入“ s”)。
如果我相信@BrtH,则使用此系统还将为您透明地转义字符串。 转义很难实现,因此,将其留给一个成熟的系统总是比自己尝试做更好。
下面是一个选择子句的随机示例:
from sqlalchemy import select
...
ham_table = meta.tables['ham']
sel = select([ham_table.c.size, ham_table.c.weight]).where(ham_table.c.taste == 'yummy')
result = meta.bind.execute(sel)
不要被“ .c。”甩掉,这只是一个约定,可以帮助他们很好地为您自动化。它们基本上为您生成列描述符,并将它们存储在表对象的.c字段下。
答案 3 :(得分:1)
在必须显式转义字符串且标准工具与要求不符的情况下,您可以要求SQLAlchemy
使用引擎的方言转义。
import sqlalchemy
engine = sqlalchemy.create_engine(...)
sqlalchemy.String('').literal_processor(dialect=engine.dialect)(value="untrusted value")
对于我来说,我需要根据用户输入动态创建一个数据库(sqlalchemy-utils
具有此功能,但是在我的情况下失败了)。
答案 4 :(得分:0)
您可以使用pymysql中的escape_string方法,然后转义:
,以便SQLAlchemy不会尝试为该变量绑定参数,这是示例
import MySQLdb
query = """ insert into.... values("{}"...) """.format(MySQLdb.escape_string(item).replace(':','\:'))
请注意,如果使用这种方式,您的代码容易受到SQL注入的攻击 安装pymysql
pip3 install pymysql