Flask makes it pretty easy to write a web application. But there are quite a few different parts to an application and to each request it handles. Knowing what happens during application setup, serving, and handling requests will help you know what’s possible in Flask and how to structure your application.
The first step in creating a Flask application is creating the application object. Each Flask application is an instance of the Flask class, which collects all configuration, extensions, and views.
from flask import Flask
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY="dev",
)
app.config.from_prefixed_env()
@app.route("/")
def index():
return "Hello, World!"
This is known as the “application setup phase”, it’s the code you write that’s outside any view functions or other handlers. It can be split up between different modules and sub-packages, but all code that you want to be part of your application must be imported in order for it to be registered.
All application setup must be completed before you start serving your application and handling requests. This is because WSGI servers divide work between multiple workers, or can be distributed across multiple machines. If the configuration changed in one worker, there’s no way for Flask to ensure consistency between other workers.
Flask tries to help developers catch some of these setup ordering issues by showing an error if setup-related methods are called after requests are handled. In that case you’ll see this error:
The setup method ‘route’ can no longer be called on the application. It has already handled its first request, any changes will not be applied consistently. Make sure all imports, decorators, functions, etc. needed to set up the application are done before running it.
However, it is not possible for Flask to detect all cases of out-of-order setup. In general, don’t do anything to modify the Flask app object and Blueprint objects from within view functions that run during requests. This includes:
@app.route, @app.errorhandler, @app.before_request, etc.app.config.app.jinja_env.app.json, instead of the default provider.Flask is a WSGI application framework. The other half of WSGI is the WSGI server. During development, Flask, through Werkzeug, provides a development WSGI server with the flask run CLI command. When you are done with development, use a production server to serve your application, see Deploying to Production.
Regardless of what server you’re using, it will follow the PEP 3333 WSGI spec. The WSGI server will be told how to access your Flask application object, which is the WSGI application. Then it will start listening for HTTP requests, translate the request data into a WSGI environ, and call the WSGI application with that data. The WSGI application will return data that is translated into an HTTP response.
environ dict.environ.The WSGI application above is a callable that behaves in a certain way. Middleware is a WSGI application that wraps another WSGI application. It’s a similar concept to Python decorators. The outermost middleware will be called by the server. It can modify the data passed to it, then call the WSGI application (or further middleware) that it wraps, and so on. And it can take the return value of that call and modify it further.
From the WSGI server’s perspective, there is one WSGI application, the one it calls directly. Typically, Flask is the “real” application at the end of the chain of middleware. But even Flask can call further WSGI applications, although that’s an advanced, uncommon use case.
A common middleware you’ll see used with Flask is Werkzeug’s ProxyFix, which modifies the request to look like it came directly from a client even if it passed through HTTP proxies on the way. There are other middleware that can handle serving static files, authentication, etc.
For us, the interesting part of the steps above is when Flask gets called by the WSGI server (or middleware). At that point, it will do quite a lot to handle the request and generate the response. At the most basic, it will match the URL to a view function, call the view function, and pass the return value back to the server. But there are many more parts that you can use to customize its behavior.
Flask.wsgi_app().RequestContext object is created. This converts the WSGI environ dict into a Request object. It also creates an AppContext object.current_app and g available.appcontext_pushed signal is sent.request and session available.session_interface, an instance of SessionInterface.route() decorator during application setup. If there is no match, the error - usually a 404, 405, or redirect - is stored to be handled later.request_started signal is sent.url_value_preprocessor() decorated functions are called.before_request() decorated functions are called. If any of these function returns a value it is treated as the response immediately.route() decorated view function associated with the matched URL is called and returns a value to be used as the response.errorhandler() decorated function that matches the exception class or HTTP error code, it is called to handle the error and return a response.Response object.after_this_request() decorated functions are called, then cleared.after_request() decorated functions are called, which can modify the response object.session_interface.request_finished signal is sent.got_request_exception signal is sent.teardown_request() decorated functions are called.request_tearing_down signal is sent.request and session are no longer available.teardown_appcontext() decorated functions are called.appcontext_tearing_down signal is sent.current_app and g are no longer available.appcontext_popped signal is sent.There are even more decorators and customization points than this, but that aren’t part of every request lifecycle. They’re more specific to certain things you might use during a request, such as templates, building URLs, or handling JSON data. See the rest of this documentation, as well as the API to explore further.
© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/stable/lifecycle/