在 Flask 中,在請(qǐng)求開始的時(shí)候用 before_request() 裝飾器實(shí)現(xiàn) 打開數(shù)據(jù)庫連接的代碼,然后在請(qǐng)求結(jié)束的時(shí)候用 before_request() 裝飾器關(guān)閉數(shù)據(jù)庫連接。在這個(gè)過程中需要配合 g 對(duì)象。
于是,在 Flask 里一個(gè)使用 SQLite 3 的簡(jiǎn)單例子就是下面這樣:
import sqlite3
from flask import g
DATABASE = '/path/to/database.db'
def connect_db():
return sqlite3.connect(DATABASE)
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
if hasattr(g, 'db'):
g.db.close()
注解
請(qǐng)記住,teardown request 在請(qǐng)求結(jié)束時(shí)總會(huì)運(yùn)行,即使 before-request 處理器 運(yùn)行失敗或者從未運(yùn)行過。我們需要確保數(shù)據(jù)庫連接在關(guān)閉的時(shí)候在那里。
按需連接
上述方法的缺陷在于,它只能用于 Flask 會(huì)執(zhí)行 before-request 處理器的場(chǎng)合下 有效,如果您想要在一個(gè)腳本或者 Python 的交互式終端中訪問數(shù)據(jù)庫。那么您必須 做一些類似下面的代碼的事情:
with app.test_request_context():
app.preprocess_request()
# now you can use the g.db object
為了激發(fā)連接代碼的執(zhí)行,使用這種方式的話,您將不能離開對(duì)請(qǐng)求上下文的依賴。 但是您使用以下方法可以使應(yīng)用程序在必要時(shí)才連接:
def get_connection():
db = getattr(g, '_db', None)
if db is None:
db = g._db = connect_db()
return db
缺點(diǎn)就是,您必須使用 db = get_connection() 而不是僅僅直接使用 g.db 來訪問數(shù)據(jù)庫連接。
簡(jiǎn)化查詢
現(xiàn)在在每個(gè)請(qǐng)求處理函數(shù)里,您都可以訪問 g.db 來獲得當(dāng)前打開的數(shù)據(jù)庫連接。 此時(shí),用一個(gè)輔助函數(shù)簡(jiǎn)化 SQLite 的使用是相當(dāng)有用的:
def query_db(query, args=(), one=False):
cur = g.db.execute(query, args)
rv = [dict((cur.description[idx][0], value)
for idx, value in enumerate(row)) for row in cur.fetchall()]
return (rv[0] if rv else None) if one else rv
相比起直接使用原始的數(shù)據(jù)指針和連接對(duì)象。這個(gè)隨手即得的小函數(shù)讓操作數(shù)據(jù)庫的操作更為輕松。 像下面這樣使用它:
for user in query_db('select * from users'):
print user['username'], 'has the id', user['user_id']
如果您只希望得到一個(gè)單獨(dú)的結(jié)果:
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 語句時(shí),使用在語句之前使用一個(gè)問號(hào),然后將參數(shù)以鏈表的形式穿進(jìn)去。 永遠(yuǎn)不要直接將他們添加到 SQL 語句中以字符串形式傳入,這樣做將會(huì)允許惡意用戶 以 SQL 注入 的方式攻擊您的應(yīng)用。
初始化數(shù)據(jù)庫模型
關(guān)系數(shù)據(jù)庫需要一個(gè)模型來定義儲(chǔ)存數(shù)據(jù)的模式,所以應(yīng)用程序通常攜帶一個(gè) schema.sql 文件用于創(chuàng)建數(shù)據(jù)庫。提供一個(gè)特定的函數(shù)來創(chuàng)建數(shù)據(jù)庫是個(gè) 不錯(cuò)的主意,以下的函數(shù)就能為您做到這件事:
from contextlib import closing
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql') as f:
db.cursor().executescript(f.read())
db.commit()
然后您就可以在 Python 的交互式終端中創(chuàng)建一個(gè)這樣的數(shù)據(jù)庫:
>>> from yourapplication import init_db
>>> init_db()
更多建議: