使用SQLite 3与Flask

在Flask中,您可以根据需要轻松实现打开数据库连接,并在上下文关闭(通常在请求结束时)时关闭它们。

于是,在 Flask 里一个使用 SQLite 3 的简单例子就是下面这样:

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函数可用于获取当前数据库连接。每当上下文被破坏时,数据库连接将被终止。

注意:如果您使用Flask 0.9或更旧版本,则需要使用flask._app_ctx_stack.top而不是g作为flask.g到请求而不是应用程序上下文。

例:

@app.route('/')
def index():
    cur = get_db().cursor()
    ...

注解

请记住,teardown request 在请求结束时总会运行,即使 before-request 处理器 运行失败或者从未运行过。 我们需要确保数据库连接在关闭的时候在那里。

按需连接

这种方法的优点(首次使用时连接)是,如果真的需要,这将只打开连接。如果你想在请求上下文之外使用这个代码,你可以通过手动打开应用程序上下文在Python shell中使用它:

with app.app_context():
    # now you can use get_db()

轻松查询

现在在每个请求处理函数里,您都可以访问 g.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模块返回这个数据库连接的dicts,这是更好的处理。更简单地说,我们可以把它放在get_db中:

db.row_factory = sqlite3.Row

这将使用Row对象而不是dicts返回查询的结果。这些是namedtuple s,因此我们可以通过索引或按键来访问它们。For example, assuming we have a sqlite3.Row called r for the rows id, FirstName, LastName, and 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 的交互式终端中创建一个这样的数据库:

>>> from yourapplication import init_db
>>> init_db()