|
|
|
@ -1,56 +1,72 @@
|
|
|
|
|
.. _tutorial-dbcon: |
|
|
|
|
|
|
|
|
|
Step 4: Request Database Connections |
|
|
|
|
------------------------------------ |
|
|
|
|
|
|
|
|
|
Now we know how we can open database connections and use them for scripts, |
|
|
|
|
but how can we elegantly do that for requests? We will need the database |
|
|
|
|
connection in all our functions so it makes sense to initialize them |
|
|
|
|
before each request and shut them down afterwards. |
|
|
|
|
|
|
|
|
|
Flask allows us to do that with the :meth:`~flask.Flask.before_request`, |
|
|
|
|
:meth:`~flask.Flask.after_request` and :meth:`~flask.Flask.teardown_request` |
|
|
|
|
decorators:: |
|
|
|
|
|
|
|
|
|
@app.before_request |
|
|
|
|
def before_request(): |
|
|
|
|
g.db = connect_db() |
|
|
|
|
|
|
|
|
|
@app.teardown_request |
|
|
|
|
def teardown_request(exception): |
|
|
|
|
db = getattr(g, 'db', None) |
|
|
|
|
if db is not None: |
|
|
|
|
db.close() |
|
|
|
|
|
|
|
|
|
Functions marked with :meth:`~flask.Flask.before_request` are called before |
|
|
|
|
a request and passed no arguments. Functions marked with |
|
|
|
|
:meth:`~flask.Flask.after_request` are called after a request and |
|
|
|
|
passed the response that will be sent to the client. They have to return |
|
|
|
|
that response object or a different one. They are however not guaranteed |
|
|
|
|
to be executed if an exception is raised, this is where functions marked with |
|
|
|
|
:meth:`~flask.Flask.teardown_request` come in. They get called after the |
|
|
|
|
response has been constructed. They are not allowed to modify the request, and |
|
|
|
|
their return values are ignored. If an exception occurred while the request was |
|
|
|
|
being processed, it is passed to each function; otherwise, `None` is passed in. |
|
|
|
|
|
|
|
|
|
We store our current database connection on the special :data:`~flask.g` |
|
|
|
|
object that Flask provides for us. This object stores information for one |
|
|
|
|
request only and is available from within each function. Never store such |
|
|
|
|
things on other objects because this would not work with threaded |
|
|
|
|
environments. That special :data:`~flask.g` object does some magic behind |
|
|
|
|
the scenes to ensure it does the right thing. |
|
|
|
|
|
|
|
|
|
For an even better way to handle such resources see the :ref:`sqlite3` |
|
|
|
|
documentation. |
|
|
|
|
|
|
|
|
|
Continue to :ref:`tutorial-views`. |
|
|
|
|
Step 3: Database Connections |
|
|
|
|
---------------------------- |
|
|
|
|
|
|
|
|
|
We have created a function for establishing a database connection with |
|
|
|
|
`create_db` but by itself that's not particularly useful. Creating and |
|
|
|
|
closing database connections all the time is very inefficient, so we want |
|
|
|
|
to keep it around for longer. Because database connections encapsulate a |
|
|
|
|
transaction we also need to make sure that only one request at the time |
|
|
|
|
uses the connection. So how can we elegantly do that with Flask? |
|
|
|
|
|
|
|
|
|
This is where the application context comes into play. So let's start |
|
|
|
|
there. |
|
|
|
|
|
|
|
|
|
Flask provides us with two contexts: the application context and the |
|
|
|
|
request context. For the time being all you have to know is that there |
|
|
|
|
are special variables that use these. For instance the |
|
|
|
|
:data:`~flask.request` variable is the request object associated with |
|
|
|
|
the current request, whereas :data:`~flask.g` is a general purpose |
|
|
|
|
variable associated with the current application context. We will go into |
|
|
|
|
the details of this a bit later. |
|
|
|
|
|
|
|
|
|
For the time being all you have to know is that you can store information |
|
|
|
|
savely on the :data:`~flask.g` object. |
|
|
|
|
|
|
|
|
|
So when do you put it on there? To do that you can make a helper |
|
|
|
|
function. The first time the function is called it will create a database |
|
|
|
|
connection for the current context and successive calls will return the |
|
|
|
|
already established connection:: |
|
|
|
|
|
|
|
|
|
def get_db(): |
|
|
|
|
"""Opens a new database connection if there is none yet for the |
|
|
|
|
current application context. |
|
|
|
|
""" |
|
|
|
|
if not hasattr(g, 'sqlite_db'): |
|
|
|
|
g.sqlite_db = connect_db() |
|
|
|
|
return g.sqlite_db |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
So now we know how to connect, but how do we properly disconnect? For |
|
|
|
|
that flask provides us with the :meth:`~flask.Flask.teardown_appcontext` |
|
|
|
|
decorator. It's executed every time the application context tears down:: |
|
|
|
|
|
|
|
|
|
@app.teardown_appcontext |
|
|
|
|
def close_db(error): |
|
|
|
|
"""Closes the database again at the end of the request.""" |
|
|
|
|
if hasattr(g, 'sqlite_db'): |
|
|
|
|
g.sqlite_db.close() |
|
|
|
|
|
|
|
|
|
Functions marked with :meth:`~flask.Flask.teardown_appcontext` are called |
|
|
|
|
every time the app context tears down. So what does this mean? |
|
|
|
|
Essentially the app context is created before the request comes in and is |
|
|
|
|
destroyed (teared down) whenever the request finishes. A teardown can |
|
|
|
|
happen because of two reasons: either everything went well (the error |
|
|
|
|
parameter will be `None`) or an exception happend in which case the error |
|
|
|
|
is passed to the teardown function. |
|
|
|
|
|
|
|
|
|
Curious about what these contexts mean? Have a look at the |
|
|
|
|
:ref:`app-context` documentation to learn more. |
|
|
|
|
|
|
|
|
|
Continue to :ref:`tutorial-dbinit`. |
|
|
|
|
|
|
|
|
|
.. hint:: Where do I put this code? |
|
|
|
|
|
|
|
|
|
If you've been following along in this tutorial, you might be wondering |
|
|
|
|
where to put the code from this step and the next. A logical place is to |
|
|
|
|
group these module-level functions together, and put your new |
|
|
|
|
``before_request`` and ``teardown_request`` functions below your existing |
|
|
|
|
``get_db`` and ``close_db`` functions below your existing |
|
|
|
|
``init_db`` function (following the tutorial line-by-line). |
|
|
|
|
|
|
|
|
|
If you need a moment to find your bearings, take a look at how the `example |
|
|
|
|