Flask 扩展的代码
下面是用来复制/粘贴的 flask_sqlite3.py 的内容:
import sqlite3
from flask import current_app
# Find the stack on which we want to store the database connection.
# Starting with Flask 0.9, the _app_ctx_stack is the correct one,
# before that we need to use the _request_ctx_stack.
try:
from flask import _app_ctx_stack as stack
except ImportError:
from flask import _request_ctx_stack as stack
class SQLite3(object):
def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
app.config.setdefault('SQLITE3_DATABASE', ':memory:')
# Use the newstyle teardown_appcontext if it's available,
# otherwise fall back to the request context
if hasattr(app, 'teardown_appcontext'):
app.teardown_appcontext(self.teardown)
else:
app.teardown_request(self.teardown)
def connect(self):
return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])
def teardown(self, exception):
ctx = stack.top
if hasattr(ctx, 'sqlite3_db'):
ctx.sqlite3_db.close()
@property
def connection(self):
ctx = stack.top
if ctx is not None:
if not hasattr(ctx, 'sqlite3_db'):
ctx.sqlite3_db = self.connect()
return ctx.sqlite3_db
那么这是这些代码做的事情:
__init__ 方法接受一个可选的应用对象,并且如果提供,会调用 init_app 。
init_app 方法使得 SQLite3 对象不需要应用对象就可以实例化。这个方法 支持工厂模式来创建应用。 init_app 会为数据库设定配置,如果不提供配置,默 认是一个内存中的数据库。此外, init_app 方法附加了 teardown 处理器。 它会试图使用新样式的应用上下文处理器,并且如果它不存在,退回到请求上下文处理 器。
接下来,我们定义了 connect 方法来打开一个数据库连接。
最后,我们添加一个 connection 属性,首次访问时打开数据库连接,并把它存储 在上下文。这也是处理资源的推荐方式:在资源第一次使用时惰性获取资源。
注意这里,我们把数据库连接通过 _app_ctx_stack.top 附加到应用上下文 的栈顶。扩展应该使用上下文的栈顶来存储它们自己的信息,并使用足够复杂的 名称。注意如果应用使用不支持它的老版本的 Flask 我们退回到 _request_ctx_stack.top 。
那么为什么我们决定在此使用基于类的方法?因为使用我们的扩展的情况看起来 会是这样:
from flask import Flask
from flask_sqlite3 import SQLite3
app = Flask(__name__)
app.config.from_pyfile('the-config.cfg')
db = SQLite3(app)
你之后可以在视图中这样使用数据库:
@app.route('/')
def show_all():
cur = db.connection.cursor()
cur.execute(...)
同样地,如果你在请求之外,而你在使用支持应用上下文 Flask 0.9 或之后的版本, 你可以用同样的方法使用数据库:
with app.app_context():
cur = db.connection.cursor()
cur.execute(...)
在 with 块的最后,销毁处理器会自动执行。
此外, init_app 方法用于支持创建应用的工厂模式:
db = Sqlite3()
# Then later on.
app = create_app('the-config.cfg')
db.init_app(app)
记住已审核的 Flask 扩展需要支持用工厂模式来创建应用(下面会解释)。
init_app 的注意事项
如你所见, init_app 不分配 app 到 self 。这是故意的!基于 类的 Flask 扩展必须只在应用传递到构造函数时在对象上存储应用。这告诉扩 展:我对使用多个应用没有兴趣。
当扩展需要找出当前的应用且它没有一个指向其的引用时,必须使用 current_app 上下文局域变量或用一种你可以显式传递应用的 方法更改 API 。
更多建议: