Merge pull request #2279 from davidism/docs-after_this_request

Clean up deferred callback doc
This commit is contained in:
David Lord 2017-05-11 22:50:29 -07:00 committed by GitHub
commit 716edfdb29

View file

@ -3,71 +3,43 @@
Deferred Request Callbacks Deferred Request Callbacks
========================== ==========================
One of the design principles of Flask is that response objects are created One of the design principles of Flask is that response objects are created and
and passed down a chain of potential callbacks that can modify them or passed down a chain of potential callbacks that can modify them or replace
replace them. When the request handling starts, there is no response them. When the request handling starts, there is no response object yet. It is
object yet. It is created as necessary either by a view function or by created as necessary either by a view function or by some other component in
some other component in the system. the system.
But what happens if you want to modify the response at a point where the What happens if you want to modify the response at a point where the response
response does not exist yet? A common example for that would be a does not exist yet? A common example for that would be a
before-request function that wants to set a cookie on the response object. :meth:`~flask.Flask.before_request` callback that wants to set a cookie on the
response object.
One way is to avoid the situation. Very often that is possible. For One way is to avoid the situation. Very often that is possible. For instance
instance you can try to move that logic into an after-request callback you can try to move that logic into a :meth:`~flask.Flask.after_request`
instead. Sometimes however moving that code there is just not a very callback instead. However, sometimes moving code there makes it more
pleasant experience or makes code look very awkward. more complicated or awkward to reason about.
As an alternative possibility you can attach a bunch of callback functions As an alternative, you can use :func:`~flask.after_this_request` to register
to the :data:`~flask.g` object and call them at the end of the request. callbacks that will execute after only the current request. This way you can
This way you can defer code execution from anywhere in the application. defer code execution from anywhere in the application, based on the current
request.
The Decorator
-------------
The following decorator is the key. It registers a function on a list on
the :data:`~flask.g` object::
from flask import g
def after_this_request(f):
if not hasattr(g, 'after_request_callbacks'):
g.after_request_callbacks = []
g.after_request_callbacks.append(f)
return f
Calling the Deferred
--------------------
Now you can use the `after_this_request` decorator to mark a function to
be called at the end of the request. But we still need to call them. For
this the following function needs to be registered as
:meth:`~flask.Flask.after_request` callback::
@app.after_request
def call_after_request_callbacks(response):
for callback in getattr(g, 'after_request_callbacks', ()):
callback(response)
return response
A Practical Example
-------------------
At any time during a request, we can register a function to be called at the At any time during a request, we can register a function to be called at the
end of the request. For example you can remember the current language of the end of the request. For example you can remember the current language of the
user in a cookie in the before-request function:: user in a cookie in a :meth:`~flask.Flask.before_request` callback::
from flask import request, after_this_request from flask import request, after_this_request
@app.before_request @app.before_request
def detect_user_language(): def detect_user_language():
language = request.cookies.get('user_lang') language = request.cookies.get('user_lang')
if language is None: if language is None:
language = guess_language_from_request() language = guess_language_from_request()
# when the response exists, set a cookie with the language
@after_this_request @after_this_request
def remember_language(response): def remember_language(response):
response.set_cookie('user_lang', language) response.set_cookie('user_lang', language)
g.language = language g.language = language