Understanding Flask Contexts: Request and Application Contexts Explained
Context Overview
In programming, context refers to the set of variables or capabilities available at a specific moment during code execution, determined by previous operations and upcoming logic.
Flask features two types of contexts: request context and application context.
Context objects in Flask act as containers that hold information during the application's runtime.
1. Request Context
Consider: How can you access current request data in a view function, such as the request URL, method, or cookies?
In Flask, you can directly use the request object within view functions to retrieve this data. The request is a request context object that stores data for the current request. Request context objects include request and session.
- request: Encapsulates HTTP request content. For example,
user = request.args.get('user')retrieves GET request parameters. - session: Tracks informaiton across user sessions. For instance,
session['name'] = user.idrecords user details, andsession.get('name')retrieves them.
2. Application Context
Application context is not persistent; it serves as a proxy for the app within the request context, known as a local proxy. It assists the request in accessing the current application and exists only during the request lifecycle.
Application context objects include current_app and g.
- current_app: Stores application-wide variables. You can print the app name with
current_app.nameor store other variables. - g: An object on the application context used for temporary storage during request processing.
Detailed Examples
Project structure:
- app.py
- utils.py
- utils1.py
1. Implementing with Session
app.py file:
import os
from flask import Flask, current_app, session, g
from flask_sqlalchemy import SQLAlchemy
from utils import log_a, log_b
from utils1 import log_a, log_b
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(14)
@app.route("/login")
def login():
return "Login page"
# Cannot be placed outside view functions
# print(current_app.name)
@app.route("/")
def index():
# Get current file name
print(current_app.name)
# Retrieve configured attributes
print(app.config['SECRET_KEY'])
return "Homepage"
# Set default session
@app.route("/set_session")
def set_session():
session["username"] = "xiaoming"
return "Session set successfully: " + session["username"]
@app.route("/index1")
def index1():
username = session.get('username')
log_a(username)
log_b(username)
return "This is index1"
Create a utility file utils.py to illustrate shared global variable current_app:
def log_a(username):
print("Log a: %s" % username)
def log_b(username):
print("Log b: %s" % username)
2. Implementing with g Object
app.py file (updated):
import os
from flask import Flask, current_app, session, g
from flask_sqlalchemy import SQLAlchemy
from utils1 import log_a, log_b
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(14)
@app.route("/login")
def login():
return "Login page"
@app.route("/")
def index():
print(current_app.name)
print(app.config['SECRET_KEY'])
return "Homepage"
@app.route("/set_session")
def set_session():
session["username"] = "xiaoming"
return "Session set successfully: " + session["username"]
@app.route("/index2")
def index2():
username = session.get('username')
g.username = username
# No parameters needed
log_a()
log_b()
return "This is index2"
if __name__ == '__main__':
app.run()
Create a utility file utils1.py:
from flask import g
def log_a():
print("Log a: %s" % g.username)
def log_b():
print("Log b: %s" % g.username)
Common Hook Functions
3.1 before_first_request
# Executes before the first request
@app.before_first_request
def first_request():
print('Executed before the first request')
3.2 before_request
# Executes before each request. Useful for adding variables to view functions
@app.before_request
def handle_before():
if not hasattr(g, 'user'):
setattr(g, 'user', 'xxxx')
print("Executed before each request")
3.3 after_request
# Executes after each request
# Note: Requires a response parameter (name can be changed)
@app.after_request
def handle_after(response):
print("Executed after each request")
return response
3.4 teardown_appcontext
# Executes after each request, regardless of exceptions
# Requires a response parameter
@app.teardown_appcontext
def handle_teardown(response):
print("handle_teardown executed")
return response
3.5 context_processor
# Context processor. Dictionary keys are available in template context
def index():
return render_template("index.html")
# Without context_processor, add manually:
# return render_template("index.html", username='check')
@app.route("/list")
def list():
return render_template("list.html")
# Each view would need manual addition
# Simplifies data passing to multiple templates
@app.context_processor
def context():
return {"username": "check"}
3.6 errorhandler
# Custom error handling for specific status codes
@app.errorhandler(404)
def page_not_found(error):
# return render_template("404.html"), 404
return "Page not found", 404
@app.errorhandler(500)
def server_error(error):
return "Internal server error", 500
@app.route("/")
def index():
# Manually trigger 404 for demonstration
abort(404)
return render_template("index.html")