Flask Extensions & Middleware
π§© Common extensions
| Extension | Purpose |
|---|---|
| Flask-SQLAlchemy | ORM |
| Flask-Migrate | DB migrations |
| Flask-WTF | forms + CSRF |
| Flask-Login | sessions/auth |
| Flask-Mail | send email |
| Flask-CORS | cross-origin requests |
| Flask-Caching | caching |
| Flask-Limiter | rate limiting |
| Flask-Session | server-side sessions |
| Flask-Marshmallow | serialization/validation |
Pattern: ext = Extension() then ext.init_app(app) β nearly universal across extensions.
Flask-Mail
pip install flask-mailfrom flask_mail import Mail, Message
app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_PORT"] = 587
app.config["MAIL_USE_TLS"] = True
mail = Mail(app)
msg = Message("Welcome!", sender="noreply@myapp.com", recipients=[user_email])
msg.body = "Thanks for signing up."
mail.send(msg)Flask-Limiter
pip install flask-limiterfrom flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(app=app, key_func=get_remote_address, default_limits=["200 per day"])
@app.route("/api/login", methods=["POST"])
@limiter.limit("5 per minute") # tighter limit on sensitive routes
def login(): ...πͺ before_request
@app.before_request
def log_request():
app.logger.info(f"{request.method} {request.path}")
@app.before_request
def check_maintenance():
if maintenance_mode() and request.path != "/maintenance":
return render_template("maintenance.html"), 503 # returning a value short-circuits the actual routeπͺ after_request
@app.after_request
def add_security_headers(response):
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
return response # must return itπͺ teardown_request
@app.teardown_request
def close_db(exception=None):
db = getattr(g, "db_connection", None)
if db is not None:
db.close()
teardown_requestruns no matter what (even on unhandled exceptions).after_requestonly runs on success.
π g object β per-request storage
from flask import g
@app.before_request
def load_user():
g.user = User.query.get(session.get("user_id"))
@app.route("/profile")
def profile():
return g.user.username if g.user else "Not logged in"
gresets on every new request β not for cross-request storage.
π§± WSGI middleware (rare, low-level)
class SimpleMiddleware:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
print(environ.get("PATH_INFO"))
return self.app(environ, start_response)
app.wsgi_app = SimpleMiddleware(app.wsgi_app)