Skip to content

Commit c1c20ac

Browse files
committed
Modify extensionsdev documentation.
1 parent fbd4886 commit c1c20ac

File tree

1 file changed

+82
-47
lines changed

1 file changed

+82
-47
lines changed

docs/extensiondev.rst

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ Now this is where your extension code goes. But how exactly should such
137137
an extension look like? What are the best practices? Continue reading
138138
for some insight.
139139

140-
141140
Initializing Extensions
142141
-----------------------
143142

@@ -165,8 +164,8 @@ classes:
165164
a remote application that uses OAuth.
166165

167166
What to use depends on what you have in mind. For the SQLite 3 extension
168-
we will need to use the class based approach because we have to use a
169-
controller object that can be used to connect to the database.
167+
we will use the class based approach because it will provide users with a
168+
manager object that handles opening and closing database connections.
170169

171170
The Extension Code
172171
------------------
@@ -175,87 +174,124 @@ Here's the contents of the `flaskext/sqlite3.py` for copy/paste::
175174

176175
from __future__ import absolute_import
177176
import sqlite3
178-
from flask import g
177+
178+
from flask import _request_ctx_stack
179179

180180
class SQLite3(object):
181-
181+
182182
def __init__(self, app):
183183
self.app = app
184184
self.app.config.setdefault('SQLITE3_DATABASE', ':memory:')
185-
186-
self.app.before_request(self.before_request)
187185
self.app.after_request(self.after_request)
186+
self.app.before_request(self.before_request)
188187

189188
def connect(self):
190189
return sqlite3.connect(self.app.config['SQLITE3_DATABASE'])
191190

192191
def before_request(self):
193-
g.sqlite3_db = self.connect()
192+
ctx = _request_ctx_stack.top
193+
ctx.sqlite3_db = self.connect()
194194

195195
def after_request(self, response):
196-
g.sqlite3_db.close()
196+
ctx = _request_ctx_stack.top
197+
ctx.sqlite3_db.close()
197198
return response
198199

199-
So here's what the lines of code do:
200-
201-
1. the ``__future__`` import is necessary to activate absolute imports.
202-
This is needed because otherwise we could not call our module
203-
`sqlite3.py` and import the top-level `sqlite3` module which actually
204-
implements the connection to SQLite.
205-
2. We create a class for our extension that sets a default configuration
206-
for the SQLite 3 database if it's not there (:meth:`dict.setdefault`)
207-
and connects two functions as before and after request handlers.
208-
3. Then it implements a `connect` function that returns a new database
209-
connection and the two handlers.
210-
211-
So why did we decide on a class based approach here? Because using that
200+
def get_db(self):
201+
ctx = _request_ctx_stack.top
202+
if ctx is not None:
203+
return ctx.sqlite3_db
204+
205+
So here's what these lines of code do:
206+
207+
1. The ``__future__`` import is necessary to activate absolute imports.
208+
Otherwise we could not call our module `sqlite3.py` and import the
209+
top-level `sqlite3` module which actually implements the connection to
210+
SQLite.
211+
2. We create a class for our extension that requires a supplied `app` object,
212+
sets a configuration for the database if it's not there
213+
(:meth:`dict.setdefault`), and attaches `before_request` and
214+
`after_request` handlers.
215+
3. Next, we define a `connect` function that opens a database connection.
216+
4. Then we set up the request handlers we bound to the app above. Note here
217+
that we're attaching our database connection to the top request context via
218+
`_request_ctx_stack.top`. Extensions should use the top context and not the
219+
`g` object to store things like database connections.
220+
5. Finally, we add a `get_db` function that simplifies access to the context's
221+
database.
222+
223+
So why did we decide on a class based approach here? Because using our
212224
extension looks something like this::
213225

214-
from flask import Flask, g
226+
from flask import Flask
215227
from flaskext.sqlite3 import SQLite3
216228

217229
app = Flask(__name__)
218230
app.config.from_pyfile('the-config.cfg')
219-
db = SQLite(app)
231+
manager = SQLite3(app)
232+
db = manager.get_db()
220233

221-
Either way you can use the database from the views like this::
234+
You can then use the database from views like this::
222235

223236
@app.route('/')
224237
def show_all():
225-
cur = g.sqlite3_db.cursor()
238+
cur = db.cursor()
226239
cur.execute(...)
227240

228-
But how would you open a database connection from outside a view function?
229-
This is where the `db` object now comes into play:
241+
Opening a database connection from outside a view function is simple.
230242

231243
>>> from yourapplication import db
232-
>>> con = db.connect()
233-
>>> cur = con.cursor()
244+
>>> cur = db.cursor()
245+
>>> cur.execute(...)
234246

235-
If you don't need that, you can go with initialization functions.
247+
Adding an `init_app` Function
248+
-----------------------------
236249

237-
Initialization Functions
238-
------------------------
250+
In practice, you'll almost always want to permit users to initialize your
251+
extension and provide an app object after the fact. This can help avoid
252+
circular import problems when a user is breaking their app into multiple files.
253+
Our extension could add an `init_app` function as follows::
239254

240-
Here's what the module would look like with initialization functions::
255+
class SQLite3(object):
241256

242-
from __future__ import absolute_import
243-
import sqlite3
244-
from flask import g
257+
def __init__(self, app=None):
258+
if app is not None:
259+
self.app = app
260+
self.init_app(self.app)
261+
else:
262+
self.app = None
245263

246-
def init_sqlite3(app):
247-
app = app
248-
app.config.setdefault('SQLITE3_DATABASE', ':memory:')
264+
def init_app(self, app):
265+
self.app = app
266+
self.app.config.setdefault('SQLITE3_DATABASE', ':memory:')
267+
self.app.after_request(self.after_request)
268+
self.app.before_request(self.before_request)
269+
270+
def connect(self):
271+
return sqlite3.connect(app.config['SQLITE3_DATABASE'])
249272

250-
@app.before_request
251-
def before_request():
252-
g.sqlite3_db = sqlite3.connect(self.app.config['SQLITE3_DATABASE'])
273+
def before_request(self):
274+
ctx = _request_ctx_stack.top
275+
ctx.sqlite3_db = self.connect()
253276

254-
@app.after_request
255-
def after_request(response):
256-
g.sqlite3_db.close()
277+
def after_request(self, response):
278+
ctx = _request_ctx_stack.top
279+
ctx.sqlite3_db.close()
257280
return response
258281

282+
def get_db(self):
283+
ctx = _request_ctx_stack.top
284+
if ctx is not None:
285+
return ctx.sqlite3_db
286+
287+
The user could then initialize the extension in one file::
288+
289+
manager = SQLite3()
290+
291+
and bind their app to the extension in another file::
292+
293+
manager.init_app(app)
294+
259295
Learn from Others
260296
-----------------
261297

@@ -276,7 +312,6 @@ designing the API.
276312
The best Flask extensions are extensions that share common idioms for the
277313
API. And this can only work if collaboration happens early.
278314

279-
280315
Approved Extensions
281316
-------------------
282317

0 commit comments

Comments
 (0)