mirror of https://github.com/mitsuhiko/flask.git
David Lord
7 years ago
7 changed files with 542 additions and 375 deletions
@ -1,144 +1,159 @@ |
|||||||
|
.. currentmodule:: flask |
||||||
|
|
||||||
.. _app-context: |
.. _app-context: |
||||||
|
|
||||||
The Application Context |
The Application Context |
||||||
======================= |
======================= |
||||||
|
|
||||||
.. versionadded:: 0.9 |
The application context keeps track of the application-level data during |
||||||
|
a request, CLI command, or other activity. Rather than passing the |
||||||
One of the design ideas behind Flask is that there are at least two |
application around to each function, the :data:`current_app` and |
||||||
different “states” in which code is executed: |
:data:`g` proxies are accessed instead. |
||||||
|
|
||||||
1. The application setup state, in which the application implicitly is |
|
||||||
on the module level. |
|
||||||
|
|
||||||
This state starts when the :class:`Flask` object is instantiated, and |
This is similar to the :doc:`/reqcontext`, which keeps track of |
||||||
it implicitly ends when the first request comes in. While the |
request-level data during a request. A corresponding application context |
||||||
application is in this state, a few assumptions are true: |
is pushed when a request context is pushed. |
||||||
|
|
||||||
- the programmer can modify the application object safely. |
Purpose of the Context |
||||||
- 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. |
|
||||||
|
|
||||||
2. In contrast, in the request handling state, a couple of other rules |
The :class:`Flask` application object has attributes, such as |
||||||
exist: |
: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 |
Flask solves this issue with the *application context*. Rather than |
||||||
(:data:`flask.request` and others) point to the current request. |
referring to an ``app`` directly, you use the the :data:`current_app` |
||||||
- any code can get hold of these objects at any time. |
proxy, which points to the application handling the current activity. |
||||||
|
|
||||||
3. There is also a third state somewhere in between 'module-level' and |
Flask automatically *pushes* an application context when handling a |
||||||
'request-handling': |
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 |
Flask will also automatically push an app context when running CLI |
||||||
how you interact with applications during request handling, but without |
commands registered with :attr:`Flask.cli` using ``@app.cli.command()``. |
||||||
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. |
|
||||||
|
|
||||||
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 |
The application context is created and destroyed as necessary. When a |
||||||
past a bunch of functionality was attached to the request context for lack |
Flask application begins handling a request, it pushes an application |
||||||
of a better solution. Since one of the pillars of Flask's design is that |
context and a :doc:`request context </reqcontext>`. When the request |
||||||
you can have more than one application in the same Python process. |
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 |
See :doc:`/reqcontext` for more information about how the contexts work |
||||||
recommended passing applications around explicitly, but that caused issues |
and the full lifecycle of a request. |
||||||
with libraries that were not designed with that in mind. |
|
||||||
|
|
||||||
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 |
If you try to access :data:`current_app`, or anything that uses it, |
||||||
implicit: whenever a request context is pushed, an application context |
outside an application context, you'll get this error message: |
||||||
will be created alongside if this is necessary. As a result, you can |
|
||||||
ignore the existence of the application context unless you need it. |
|
||||||
|
|
||||||
The second way is the explicit way using the |
.. code-block:: pytb |
||||||
:meth:`~flask.Flask.app_context` method:: |
|
||||||
|
|
||||||
from flask import Flask, current_app |
RuntimeError: Working outside of application context. |
||||||
|
|
||||||
app = Flask(__name__) |
This typically means that you attempted to use functionality that |
||||||
with app.app_context(): |
needed to interface with the current application object in some way. |
||||||
# within this block, current_app points to app. |
To solve this, set up an application context with app.app_context(). |
||||||
print current_app.name |
|
||||||
|
|
||||||
The application context is also used by the :func:`~flask.url_for` |
If you see that error while configuring your application, such as when |
||||||
function in case a ``SERVER_NAME`` was configured. This allows you to |
initializing an extension, you can push a context manually since you |
||||||
generate URLs even in the absence of a request. |
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 |
def create_app(): |
||||||
not been explicitly set, a ``RuntimeError`` will be raised. :: |
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 |
If you see that error somewhere else in your code not related to |
||||||
moves between threads and it will not be shared between requests. As such |
configuring the application, it most likely indicates that you should |
||||||
it is the perfect place to store database connection information and other |
move that code into a view function or CLI command. |
||||||
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. |
|
||||||
|
|
||||||
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 |
The application context is a good place to store common data during a |
||||||
on a per-request or usage case. For instance, database connections are |
request or CLI command. Flask provides the :data:`g object <g>` for this |
||||||
destined to go there. When storing things on the application context |
purpose. It is a simple namespace object that has the same lifetime as |
||||||
unique names should be chosen as this is a place that is shared between |
an application context. |
||||||
Flask applications and extensions. |
|
||||||
|
|
||||||
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. |
A common use for :data:`g` is to manage resources during a request. |
||||||
2. a context teardown based resource deallocation. |
|
||||||
|
|
||||||
Generally there would be a ``get_X()`` function that creates resource |
1. ``get_X()`` creates resource ``X`` if it does not exist, caching it |
||||||
``X`` if it does not exist yet and otherwise returns the same resource, |
as ``g.X``. |
||||||
and a ``teardown_X()`` function that is registered as teardown handler. |
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 |
from flask import g |
||||||
|
|
||||||
def get_db(): |
def get_db(): |
||||||
db = getattr(g, '_database', None) |
if 'db' not in g: |
||||||
if db is None: |
g.db = connect_to_database() |
||||||
db = g._database = connect_to_database() |
|
||||||
return db |
return g.db |
||||||
|
|
||||||
@app.teardown_appcontext |
@app.teardown_appcontext |
||||||
def teardown_db(exception): |
def teardown_db(): |
||||||
db = getattr(g, '_database', None) |
db = g.pop('db', None) |
||||||
|
|
||||||
if db is not None: |
if db is not None: |
||||||
db.close() |
db.close() |
||||||
|
|
||||||
The first time ``get_db()`` is called the connection will be established. |
During a request, every call to ``get_db()`` will return the same |
||||||
To make this implicit a :class:`~werkzeug.local.LocalProxy` can be used:: |
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 |
from werkzeug.local import LocalProxy |
||||||
db = LocalProxy(get_db) |
db = LocalProxy(get_db) |
||||||
|
|
||||||
That way a user can directly access ``db`` which internally calls |
Accessing ``db`` will call ``get_db`` internally, in the same way that |
||||||
``get_db()``. |
: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`. |
||||||
|
Loading…
Reference in new issue