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