Ep. 26 Flask before and after request
10 Apr 2019
Flask before and after request functions | Learning Flask Ep. 26
In this short article, we're going to be taking a look at some of the ways we can run functions before and after a request in Flask, using the before_request
and after_request
decorators and a few others.
We'll start out with a very basic Flask application:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
print("index is running!")
return "Hello world"
if __name__ == "__main__":
app.run()
before_request
The before_request
decorator allows us to create a function that will run before each request.
We can use it by decorating a function with @app.before_request
:
@app.before_request
def before_request_func():
print("before_request is running!")
Adding this function to our application and making a request to the route /
, we get the following output in the terminal:
before_request is running!
index is running!
before_request
functions are ideal for tasks such as:
Opening database connections
Loading a user from the session
Working with the flask g object
Functions decorated with before_request
are not required to return anything, however - If a before_request
function returns a non None
value, it will be handled as if it was the return value for the view and any further request handling is stopped.
For example:
@app.before_request
def before_request_func():
print("before_request is running!")
return "Intercepted by before_request"
If you were to make any requests or go to any route in your application, you'd see Intercepted by before_request
as the return value.
Let's import session
and g
and work with them in the before_request
function:
from flask import session, g
To work with the session
object, we'll need to assign a secret_key
to our app:
app.secret_key = "MySecretKey1234"
For the sake of this example, we'll just assign a key & value to the session
object and set an attribute username
on the g
object.
You would typically use a function like this to:
Get a unique user ID from the session
Fetch the user from a database
Assign the user to the g object
Here's the example:
@app.before_request
def before_request_func():
session["foo"] = "bar"
g.username = "root"
print("before_request is running!")
Running the app and accessing our route gives us the same output as before, so let's access these values from our route:
@app.route("/")
def index():
username = g.username
foo = session.get("foo")
print("index is running!", username, foo)
return "Hello world"
Running the app and accessing our route, we see the following output in the terminal:
before_request is running!
index is running! root bar
We're able to access session["foo"]
and g.username
which we set in before_request
as it's available in the context of the request.
before_first_request
Functions decorated with @app.before_first_request
will run once before the first request to this instance of the application:
@app.before_first_request
def before_first_request_func():
print("This function will run once")
Running the app and making a couple of requests, we see the following output:
This function will run once
before_request is running!
index is running! root bar
127.0.0.1 - - [10/Apr/2019 13:42:10] "GET / HTTP/1.1" 200 -
before_request is running!
index is running! root bar
127.0.0.1 - - [10/Apr/2019 13:42:12] "GET / HTTP/1.1" 200 -
As you'll notice, the before_first_request
fucntion only ran once before the very first request to the app and is ignored on subsequent requests.
Depending on your application, you may want to use a before_first_request
function to do some database maintenance or any other task that only needs to happen once.
after_request
Functions decorated with after_request
work in the same way as before_request
, except they are run after each request.
An important thing to note is that any after_request
functions must take and return an instance of the Flask response class.
Here's a simple example:
@app.after_request
def after_request_func(response):
print("after_request is running!")
return response
Running our app and making a request to our route, we see:
before_request is running!
index is running! root bar
after_request is running!
after_request
functions will be run after every request and provide access to the request context, meaning we still have access to ssession
and g
. For example:
@app.after_request
def after_request_func(response):
username = g.username
foo = session.get("foo")
print("after_request is running!", username, foo)
return response
At this point you might be thinking; This is a great place to do something like close a database connection, and you'd be right.
However something to note is that any functions decorated with after_request
will NOT run if your application throws an exception.
We can illustrate this by raising an exception in our route:
@app.route("/")
def index():
raise ValueError("after_request will not run")
username = g.username
foo = session.get("foo")
print("index is running!", username, foo)
return "Hello world"
Running our app and accessing our route, we see:
This function will run once
before_request is running!
127.0.0.1 - - [10/Apr/2019 14:02:17] "GET / HTTP/1.1" 500 -
Traceback (most recent call last):
# etc ...
As expected, both our before_first_request
and before_request
functions ran, however raising the ValueError
in our route brought our application to a halt and after_request
didn't run.
Fortunately, we can get around this with teardown_request
.
teardown_request
Functions decorated with teardown_request
behave similarly to after_request
functions, however, they have the added benefit of being triggered regardless of any exceptions raised.
This makes teardown_request
functions a great place to do any cleanup operations after requests, as we know these function will always run.
Note - In debug mode, Flask will not tear down a request on exception immidiately.
From the Flask docs:
"Generally teardown functions must take every necessary step to avoid that they will fail. If they do execute code that might fail they will have to surround the execution of these code by try/except statements and log occurring errors."
When a teardown function was called because of an exception it will be passed an error object.
@app.teardown_request
def teardown_request_func(error=None):
print("teardown_request is running!")
if error:
# Log the error
print(str(error))
Due to the nature of how Flask handles teardown_request
in debug mode, we'll run export FLASK_ENV=production
to see our function in action.
Running our app without raising the ValueError
in our route, we see:
This function will run once
before_request is running!
index is running! root bar
after_request is running! root bar
teardown_request is running!
We can see that teardown_request
ran as expected as it will run regardless of whether an exception was raised or not.
Running our app and raising the ValueError
in our route, we see:
This function will run once
before_request is running!
[2019-04-10 15:08:59,003] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
...
teardown_request is running!
after_request will not run
Digging through the debug message in the console, we see that teardown_request
has run and the message raised in the exception has been passed to it and printed, whereas after_request
was not triggered.
All together
Putting everything together, our application looks like this:
from flask import Flask
from flask import session, g
app = Flask(__name__)
app.secret_key = "iufh4857o3yfhh3"
@app.before_first_request
def before_first_request_func():
"""
This function will run once before the first request to this instance of the application.
You may want to use this function to create any databases/tables required for your app.
"""
print("This function will run once ")
@app.before_request
def before_request_func():
"""
This function will run before every request. Let's add something to the session & g.
It's a good place for things like establishing database connections, retrieving
user information from the session, assigning values to the flask g object etc..
We have access to the request context.
"""
session["foo"] = "bar"
g.username = "root"
print("before_request is running!")
@app.route("/")
def index():
"""
A simple route that gets a session value added by the before_request function,
the g.username and returns a string.
Uncommenting `raise ValueError` will throw an error but the teardown_request
funtion will still run.
"""
# raise ValueError("after_request will not run")
username = g.username
foo = session.get("foo")
print("index is running!", username, foo)
return "Hello world"
@app.after_request
def after_request_func(response):
"""
This function will run after a request, as long as no exceptions occur.
It must take and return the same parameter - an instance of response_class.
This is a good place to do some application cleanup.
"""
username = g.username
foo = session.get("foo")
print("after_request is running!", username, foo)
return response
@app.teardown_request
def teardown_request_func(error=None):
"""
This function will run after a request, regardless if an exception occurs or not.
It's a good place to do some cleanup, such as closing any database connections.
If an exception is raised, it will be passed to the function.
You should so everything in your power to ensure this function does not fail, so
liberal use of try/except blocks is recommended.
"""
print("teardown_request is running!")
if error:
# Log the error
print(str(error))
if __name__ == "__main__":
app.run()
Wrapping up
Using some of Flasks built in decorators allows us to add another layer of functionality and validation to our applications and should be taken advantage of!
We've only provided a few examples here, and you'll find other useful functions for working with requests, both before and after over at the link to the Flask API documentation below:
Last modified · 10 Apr 2019 Reference : https://pythonise.com/series/learning-flask/python-before-after-request#related
Last updated
Was this helpful?