One of the design principles of Flask is that response objects are created and passed down a chain of potential callbacks that can modify them or replace them. When the request handling starts, there is no response object yet. It is created as necessary either by a view function or by some other component in the system.
But what happens if you want to modify the response at a point where the response 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.
One way is to avoid the situation. Very often that is possible. For instance you can try to move that logic into an after-request callback instead. Sometimes however moving that code there is just not a very pleasant experience or makes code look very awkward.
As an alternative possibility you can attach a bunch of callback functions to the g
object and call them at the end of the request. This way you can defer code execution from anywhere in the application.
The following decorator is the key. It registers a function on a list on the 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
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 after_request()
callback:
@app.after_request def call_after_request_callbacks(response): for callback in getattr(g, 'after_request_callbacks', ()): callback(response) return response
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 user in a cookie in the before-request function:
from flask import request @app.before_request def detect_user_language(): language = request.cookies.get('user_lang') if language is None: language = guess_language_from_request() @after_this_request def remember_language(response): response.set_cookie('user_lang', language) g.language = language
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/0.12.x/patterns/deferredcallbacks/