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