我不是 Python 程序员,但我做 SQL 已经很久了。我什至写了自己的 ORM。我的建议是不要编写自己的 SQL 查询生成器。有无数微妙的问题,尤其是安全问题。我将在下面详细说明其中的一些。
改为使用成熟的 SQL 查询构建器或 ORM。他们已经处理了这些问题。这是一个使用 SQLAlchemy 的示例。
from datetime import date
from sqlalchemy import create_engine, MetaData
# Connect to the database with debugging on.
engine = create_engine('sqlite:///test.sqlite', echo=True)
conn = engine.connect()
# Read the schemas from the database
meta = MetaData()
meta.reflect(bind=engine)
# INSERT INTO users (name, birthday, state, country) VALUES (?, ?, ?, ?)
users = meta.tables['users']
conn.execute(
users.insert().values(name="Yarrow Hock", birthday=date(1977, 1, 23), state="NY", country="US")
)
SQLAlchemy 可以执行所有 SQL 操作,并且可以使用不同的 SQL 变体。您还可以获得类型安全性。
conn.execute(
users.insert().values(name="Yarrow Hock", birthday="in the past", state="NY", country="US")
)
sqlalchemy.exc.StatementError: (exceptions.TypeError) SQLite Date type only accepts Python date objects as input. [SQL: u'INSERT INTO users (name, birthday, state, country) VALUES (?, ?, ?, ?)']
insert into table values (...) 依赖于列定义顺序
这依赖于模式中定义的列顺序。这留下了两个问题。首先是可读性问题。
add2Db(db, 'some_table', (1, 39, 99, 45, 'papa foxtrot', 0, 42, 0, 6)
这是什么意思?读者无法判断。他们必须深入研究架构并计算列数以找出每个值的含义。
其次是维护问题。如果出于任何原因更改了架构并且列顺序不完全相同,这可能会导致一些极难发现的错误。比如……
create table users ( name text, birthday date, state text, country text );
vs
create table users ( name text, birthday date, country text, state text );
add2Db(db, 'users', ('Yarrow Hock', date(1977, 1, 23), 'NY', 'US'));
该插入将以任一列顺序静默“工作”。
您可以通过传入字典并使用列名的键来解决此问题。
add2Db(db, 'users', (name="Yarrow Hock", birthday=date(1977, 1, 23), state="NY", country="US"));
然后我们会生成如下查询:
insert into users
(name, birthday, state, country)
values (?, ?, ?, ?)
这导致了下一个更大的问题。
SQL 注入攻击
现在这带来了一个新问题。如果我们只是将表名和列名粘贴到查询中,就会让我们面临最常见的安全漏洞之一,SQL Injection Attack。这就是人们可以制作一个值的地方,当它在 SQL 语句中天真地使用时会导致查询执行其他操作。喜欢Little Bobby Tables。
虽然? 可以防止值的 SQL 注入,但仍然可以通过列名进行注入。不能保证列名是可信的。也许它们来自网络表单的参数?
Protecting table and column names is complicated 容易出错。
您编写的 SQL 越多,您就越容易受到注入攻击。
您必须为其他所有内容编写代码。
好的,你已经完成了insert。现在update? select?不要忘记子查询、分组依据、联合、连接...
如果你想写一个 SQL 查询构建器,太棒了!相反,如果您有使用 SQL 的工作要做,那么编写另一个 SQL 查询构建器不是您的工作。
其他人更难理解。
很有可能任何给定的 Python 程序员都知道 SQLAlchemy 是如何工作的,如果他们不知道的话,还有大量的教程和文档。他们不可能知道您自制的 SQL 函数,而且您必须编写所有教程和文档。