-
-
Notifications
You must be signed in to change notification settings - Fork 16k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2685 from davidism/app-context-docs
rework context docs
- Loading branch information
Showing
7 changed files
with
542 additions
and
375 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,159 @@ | ||
.. currentmodule:: flask | ||
|
||
.. _app-context: | ||
|
||
The Application Context | ||
======================= | ||
|
||
.. versionadded:: 0.9 | ||
|
||
One of the design ideas behind Flask is that there are at least two | ||
different “states” in which code is executed: | ||
|
||
1. The application setup state, in which the application implicitly is | ||
on the module level. | ||
The application context keeps track of the application-level data during | ||
a request, CLI command, or other activity. Rather than passing the | ||
application around to each function, the :data:`current_app` and | ||
:data:`g` proxies are accessed instead. | ||
|
||
This state starts when the :class:`Flask` object is instantiated, and | ||
it implicitly ends when the first request comes in. While the | ||
application is in this state, a few assumptions are true: | ||
This is similar to the :doc:`/reqcontext`, which keeps track of | ||
request-level data during a request. A corresponding application context | ||
is pushed when a request context is pushed. | ||
|
||
- the programmer can modify the application object safely. | ||
- no request handling happened so far | ||
- you have to have a reference to the application object in order to | ||
modify it, there is no magic proxy that can give you a reference to | ||
the application object you're currently creating or modifying. | ||
Purpose of the Context | ||
---------------------- | ||
|
||
2. In contrast, in the request handling state, a couple of other rules | ||
exist: | ||
The :class:`Flask` application object has attributes, such as | ||
:attr:`~Flask.config`, that are useful to access within views and | ||
:doc:`CLI commands </cli>`. However, importing the ``app`` instance | ||
within the modules in your project is prone to circular import issues. | ||
When using the :doc:`app factory pattern </patterns/appfactories>` or | ||
writing reusable :doc:`blueprints </blueprints>` or | ||
:doc:`extensions </extensions>` there won't be an ``app`` instance to | ||
import at all. | ||
|
||
- while a request is active, the context local objects | ||
(:data:`flask.request` and others) point to the current request. | ||
- any code can get hold of these objects at any time. | ||
Flask solves this issue with the *application context*. Rather than | ||
referring to an ``app`` directly, you use the the :data:`current_app` | ||
proxy, which points to the application handling the current activity. | ||
|
||
3. There is also a third state somewhere in between 'module-level' and | ||
'request-handling': | ||
Flask automatically *pushes* an application context when handling a | ||
request. View functions, error handlers, and other functions that run | ||
during a request will have access to :data:`current_app`. | ||
|
||
Sometimes you are dealing with an application in a way that is similar to | ||
how you interact with applications during request handling, but without | ||
there being an active request. Consider, for instance, that you're | ||
sitting in an interactive Python shell and interacting with the | ||
application, or a command line application. | ||
Flask will also automatically push an app context when running CLI | ||
commands registered with :attr:`Flask.cli` using ``@app.cli.command()``. | ||
|
||
The application context is what powers the :data:`~flask.current_app` | ||
context local. | ||
|
||
Purpose of the Application Context | ||
---------------------------------- | ||
Lifetime of the Context | ||
----------------------- | ||
|
||
The main reason for the application's context existence is that in the | ||
past a bunch of functionality was attached to the request context for lack | ||
of a better solution. Since one of the pillars of Flask's design is that | ||
you can have more than one application in the same Python process. | ||
The application context is created and destroyed as necessary. When a | ||
Flask application begins handling a request, it pushes an application | ||
context and a :doc:`request context </reqcontext>`. When the request | ||
ends it pops the request context then the application context. | ||
Typically, an application context will have the same lifetime as a | ||
request. | ||
|
||
So how does the code find the “right” application? In the past we | ||
recommended passing applications around explicitly, but that caused issues | ||
with libraries that were not designed with that in mind. | ||
See :doc:`/reqcontext` for more information about how the contexts work | ||
and the full lifecycle of a request. | ||
|
||
A common workaround for that problem was to use the | ||
:data:`~flask.current_app` proxy later on, which was bound to the current | ||
request's application reference. Since creating such a request context is | ||
an unnecessarily expensive operation in case there is no request around, | ||
the application context was introduced. | ||
|
||
Creating an Application Context | ||
------------------------------- | ||
Manually Push a Context | ||
----------------------- | ||
|
||
There are two ways to make an application context. The first one is | ||
implicit: whenever a request context is pushed, an application context | ||
will be created alongside if this is necessary. As a result, you can | ||
ignore the existence of the application context unless you need it. | ||
If you try to access :data:`current_app`, or anything that uses it, | ||
outside an application context, you'll get this error message: | ||
|
||
The second way is the explicit way using the | ||
:meth:`~flask.Flask.app_context` method:: | ||
.. code-block:: pytb | ||
from flask import Flask, current_app | ||
RuntimeError: Working outside of application context. | ||
app = Flask(__name__) | ||
with app.app_context(): | ||
# within this block, current_app points to app. | ||
print current_app.name | ||
This typically means that you attempted to use functionality that | ||
needed to interface with the current application object in some way. | ||
To solve this, set up an application context with app.app_context(). | ||
The application context is also used by the :func:`~flask.url_for` | ||
function in case a ``SERVER_NAME`` was configured. This allows you to | ||
generate URLs even in the absence of a request. | ||
If you see that error while configuring your application, such as when | ||
initializing an extension, you can push a context manually since you | ||
have direct access to the ``app``. Use :meth:`~Flask.app_context` in a | ||
``with`` block, and everything that runs in the block will have access | ||
to :data:`current_app`. :: | ||
|
||
If no request context has been pushed and an application context has | ||
not been explicitly set, a ``RuntimeError`` will be raised. :: | ||
def create_app(): | ||
app = Flask(__name__) | ||
|
||
RuntimeError: Working outside of application context. | ||
with app.app_context(): | ||
init_db() | ||
|
||
Locality of the Context | ||
----------------------- | ||
return app | ||
|
||
The application context is created and destroyed as necessary. It never | ||
moves between threads and it will not be shared between requests. As such | ||
it is the perfect place to store database connection information and other | ||
things. The internal stack object is called :data:`flask._app_ctx_stack`. | ||
Extensions are free to store additional information on the topmost level, | ||
assuming they pick a sufficiently unique name and should put their | ||
information there, instead of on the :data:`flask.g` object which is reserved | ||
for user code. | ||
If you see that error somewhere else in your code not related to | ||
configuring the application, it most likely indicates that you should | ||
move that code into a view function or CLI command. | ||
|
||
For more information about that, see :ref:`extension-dev`. | ||
|
||
Context Usage | ||
------------- | ||
Storing Data | ||
------------ | ||
|
||
The context is typically used to cache resources that need to be created | ||
on a per-request or usage case. For instance, database connections are | ||
destined to go there. When storing things on the application context | ||
unique names should be chosen as this is a place that is shared between | ||
Flask applications and extensions. | ||
The application context is a good place to store common data during a | ||
request or CLI command. Flask provides the :data:`g object <g>` for this | ||
purpose. It is a simple namespace object that has the same lifetime as | ||
an application context. | ||
|
||
The most common usage is to split resource management into two parts: | ||
.. note:: | ||
The ``g`` name stands for "global", but that is referring to the | ||
data being global *within a context*. The data on ``g`` is lost | ||
after the context ends, and it is not an appropriate place to store | ||
data between requests. Use the :data:`session` or a database to | ||
store data across requests. | ||
|
||
1. an implicit resource caching on the context. | ||
2. a context teardown based resource deallocation. | ||
A common use for :data:`g` is to manage resources during a request. | ||
|
||
Generally there would be a ``get_X()`` function that creates resource | ||
``X`` if it does not exist yet and otherwise returns the same resource, | ||
and a ``teardown_X()`` function that is registered as teardown handler. | ||
1. ``get_X()`` creates resource ``X`` if it does not exist, caching it | ||
as ``g.X``. | ||
2. ``teardown_X()`` closes or otherwise deallocates the resource if it | ||
exists. It is registered as a :meth:`~Flask.teardown_appcontext` | ||
handler. | ||
|
||
This is an example that connects to a database:: | ||
For example, you can manage a database connection using this pattern:: | ||
|
||
import sqlite3 | ||
from flask import g | ||
|
||
def get_db(): | ||
db = getattr(g, '_database', None) | ||
if db is None: | ||
db = g._database = connect_to_database() | ||
return db | ||
if 'db' not in g: | ||
g.db = connect_to_database() | ||
|
||
return g.db | ||
|
||
@app.teardown_appcontext | ||
def teardown_db(exception): | ||
db = getattr(g, '_database', None) | ||
def teardown_db(): | ||
db = g.pop('db', None) | ||
|
||
if db is not None: | ||
db.close() | ||
|
||
The first time ``get_db()`` is called the connection will be established. | ||
To make this implicit a :class:`~werkzeug.local.LocalProxy` can be used:: | ||
During a request, every call to ``get_db()`` will return the same | ||
connection, and it will be closed automatically at the end of the | ||
request. | ||
|
||
You can use :class:`~werkzeug.local.LocalProxy` to make a new context | ||
local from ``get_db()``:: | ||
|
||
from werkzeug.local import LocalProxy | ||
db = LocalProxy(get_db) | ||
|
||
That way a user can directly access ``db`` which internally calls | ||
``get_db()``. | ||
Accessing ``db`` will call ``get_db`` internally, in the same way that | ||
:data:`current_app` works. | ||
|
||
---- | ||
|
||
If you're writing an extension, :data:`g` should be reserved for user | ||
code. You may store internal data on the context itself, but be sure to | ||
use a sufficiently unique name. The current context is accessed with | ||
:data:`_app_ctx_stack.top <_app_ctx_stack>`. For more information see | ||
:doc:`extensiondev`. | ||
|
||
|
||
Events and Signals | ||
------------------ | ||
|
||
The application will call functions registered with | ||
:meth:`~Flask.teardown_appcontext` when the application context is | ||
popped. | ||
|
||
If :data:`~signals.signals_available` is true, the following signals are | ||
sent: :data:`appcontext_pushed`, :data:`appcontext_tearing_down`, and | ||
:data:`appcontext_popped`. |
Oops, something went wrong.