使用 SQLite 3 与 Flask¶
在 Flask 中,您可以轻松实现按需打开数据库连接,并在上下文消失(通常在请求结束时)时关闭它们。
以下是有关如何将 SQLite 3 与 Flask 配合使用的简单示例
import sqlite3
from flask import g
DATABASE = '/path/to/database.db'
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
现在,要使用数据库,应用程序必须具有活动应用程序上下文(如果正在进行请求,则始终为真),或自行创建应用程序上下文。此时,可以使用 get_db
函数获取当前数据库连接。每当上下文被销毁时,数据库连接将被终止。
示例
@app.route('/')
def index():
cur = get_db().cursor()
...
注意
请记住,即使请求前处理程序失败或从未执行,也会始终执行清理请求和 appcontext 函数。因此,我们必须在此处确保在关闭数据库之前数据库存在。
按需连接¶
这种方法(在首次使用时连接)的好处是,它只会根据实际需要打开连接。如果您想在请求上下文之外使用此代码,可以通过手动打开应用程序上下文在 Python shell 中使用它
with app.app_context():
# now you can use get_db()
轻松查询¶
现在,在每个请求处理函数中,您可以访问 get_db() 以获取当前打开的数据库连接。为了简化使用 SQLite 的过程,行工厂函数非常有用。它对从数据库返回的每个结果执行,以转换结果。例如,为了获取字典而不是元组,可以将其插入到我们在上面创建的 get_db
函数中
def make_dicts(cursor, row):
return dict((cursor.description[idx][0], value)
for idx, value in enumerate(row))
db.row_factory = make_dicts
这将使 sqlite3 模块为此数据库连接返回字典,这更容易处理。更简单的方法是,我们可以将其放入 get_db
中
db.row_factory = sqlite3.Row
这将使用行对象而不是字典来返回查询结果。这些是 namedtuple
,因此我们可以通过索引或键访问它们。例如,假设我们有一个名为 r
的 sqlite3.Row
,用于行 id
、FirstName
、LastName
和 MiddleInitial
>>> # You can get values based on the row's name
>>> r['FirstName']
John
>>> # Or, you can get them based on index
>>> r[1]
John
# Row objects are also iterable:
>>> for value in r:
... print(value)
1
John
Doe
M
此外,最好提供一个查询函数,该函数将获取游标、执行和获取结果相结合
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
这个方便的小功能与行工厂结合使用,使使用数据库比仅使用原始游标和连接对象更加愉快。
以下是如何使用它
for user in query_db('select * from users'):
print(user['username'], 'has the id', user['user_id'])
或者,如果您只需要一个结果
user = query_db('select * from users where username = ?',
[the_username], one=True)
if user is None:
print('No such user')
else:
print(the_username, 'has the id', user['user_id'])
要将变量部分传递到 SQL 语句,请在语句中使用问号,并将参数作为列表传递。切勿使用字符串格式直接将它们添加到 SQL 语句中,因为这使得可以利用 SQL 注入 攻击应用程序。
初始架构¶
关系数据库需要架构,因此应用程序通常会提供一个 schema.sql 文件来创建数据库。提供一个基于该架构创建数据库的函数是一个好主意。此函数可以为您完成此操作
def init_db():
with app.app_context():
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
然后,您可以从 Python shell 创建这样的数据库
>>> from yourapplication import init_db
>>> init_db()