1. Flask Cheat Sheet
- 1. Flask Cheat Sheet
- 1.1 Getting Started
- 1.2 Routing
- 1.3 Templates
- 1.4 Forms
- 1.5 Databases
- 1.6 Static Files
- 1.7 Blueprints
- 1.8 Flask Extensions
- 1.9 Testing
- 1.10 Deployment
- 1.11 Security
- 1.12 Logging
- 1.13 Flask CLI
- 1.14 Context Processors
- 1.15 Error Handling
- 1.16 Flask-RESTful
- 1.17 Session Management
- 1.18 Flask-CORS
- 1.19 Testing
- 1.20 Deployment
- 1.21 Security
- 1.22 Logging
- 1.23 Flask CLI
- 1.24 Context Processors
- 1.25 Testing
- 1.26 Deployment
- 1.27 Security
- 1.28 Logging
- 1.29 Flask CLI
- 1.30 Context Processors
- 1.31 Error Handling
- 1.32 Flask-RESTful
- 1.33 Session Management
- 1.34 Flask-CORS
- 1.35 Signals
- 1.36 Flask-Limiter
- 1.37 Flask-APScheduler
- 1.38 Flask-Sitemap
- 1.39 Flask-WTF CSRF Protection
- 1.40 Flask-FlatPages
- 1.41 Flask-Assets
- 1.42 Flask-Babel
- 1.43 Flask-SocketIO
- 1.44 Flask-Principal
- 1.45 Flask-JWT-Extended
- 1.46 Flask-Uploads
- 1.47 Flask-Mail
- 1.48 Flask-APScheduler
- 1.49 Flask-Sitemap
- 1.50 Flask-WTF CSRF Protection
- 1.51 Tips and Best Practices
This cheat sheet provides an exhaustive overview of the Flask micro web framework, covering essential commands, concepts, and code snippets for efficient Flask development. It aims to be a one-stop reference for common tasks and best practices.
1.1 Getting Started
1.1.1 Installation
pip install flask
Consider using a virtual environment:
python -m venv venv
source venv/bin/activate # On Linux/macOS
venv\Scripts\activate # On Windows
1.1.2 Basic App Structure
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
1.1.3 Running the App
python your_app_name.py
1.2 Routing
1.2.1 Basic Route
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Index Page'
if __name__ == '__main__':
app.run(debug=True)
1.2.2 Dynamic Routes
from flask import Flask
app = Flask(__name__)
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return f'Post {post_id}'
if __name__ == '__main__':
app.run(debug=True)
1.2.3 HTTP Methods
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return "Do the login"
else:
return "Show the login form"
if __name__ == '__main__':
app.run(debug=True)
1.2.4 URL Building
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
return 'Index'
@app.route('/login')
def login():
return 'Login'
@app.route('/user/<username>')
def profile(username):
return f'{username}\'s profile'
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
if __name__ == '__main__':
app.run(debug=True)
1.3 Templates
1.3.1 Basic Template Rendering
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
1.3.2 Template (templates/hello.html)
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
</body>
</html>
1.3.3 Template Inheritance
Base template (templates/base.html
):
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Website{% endblock %}</title>
</head>
<body>
<header>
<h1>{% block header %}My Website{% endblock %}</h1>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2025 My Website</p>
</footer>
</body>
</html>
Child template (templates/hello.html
):
{% extends "base.html" %}
{% block title %}Hello{% endblock %}
{% block content %}
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
{% endblock %}
1.3.4 Jinja2 Template Engine
{{ variable }}
: Outputs a variable.{% tag %}
: Template logic tag (e.g.,for
,if
).{{ variable|filter }}
: Applies a filter to a variable.{% extends "base.html" %}
: Extends a base template.{% block block_name %}{% endblock %}
: Defines a block for template inheritance.{% include "template_name.html" %}
: Includes another template.{% url_for 'view_name' arg1=value1 %}
: Generates a URL for a view.
1.3.5 Common Template Filters
safe
: Marks a string as safe for HTML output.capitalize
: Capitalizes the first character of a string.lower
,upper
: Converts a string to lowercase or uppercase.title
: Converts a string to title case.trim
: Removes leading and trailing whitespace.striptags
: Strips SGML/XML tags.length
: Returns the length of a value.default(value, default_value='')
: Provides a default value if a variable is undefined.replace(old, new, count=None)
: Replaces occurrences of a substring.format(value, *args, **kwargs)
: Formats a string using Python's string formatting.
1.4 Forms
1.4.1 Basic Form
<form method="post">
<label for="name">Name:</label><br>
<input type="text" id="name" name="name"><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email"><br>
<input type="submit" value="Submit">
</form>
1.4.2 Using Flask-WTF
Installation:
pip install flask-wtf
Configuration (in your app):
import os
from flask import Flask
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'your_secret_key'
1.4.3 Define a Form (forms.py)
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField, EmailField, BooleanField
from wtforms.validators import DataRequired, Length, Email
class MyForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(min=2, max=20)])
email = EmailField('Email', validators=[DataRequired(), Email()])
message = TextAreaField('Message', validators=[DataRequired()])
agree = BooleanField('I agree to the terms', validators=[DataRequired()])
submit = SubmitField('Submit')
1.4.4 Render a Form in a Template
<form method="post">
{{ form.csrf_token }}
<div class="form-group">
{{ form.name.label }}<br>
{{ form.name(class="form-control") }}
{% if form.name.errors %}
<ul class="errors">
{% for error in form.name.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="form-group">
{{ form.email.label }}<br>
{{ form.email(class="form-control") }}
{% if form.email.errors %}
<ul class="errors">
{% for error in form.email.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="form-group">
{{ form.message.label }}<br>
{{ form.message(class="form-control") }}
{% if form.message.errors %}
<ul class="errors">
{% for error in form.message.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="form-group">
{{ form.agree.label }}
{{ form.agree }}
{% if form.agree.errors %}
<ul class="errors">
{% for error in form.agree.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
1.4.5 Process Form Data in a View
from flask import Flask, render_template, request, redirect, url_for
from forms import MyForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
@app.route('/form', methods=['GET', 'POST'])
def my_form_view():
form = MyForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
message = form.message.data
# Process the data (e.g., save to database, send email)
return redirect(url_for('success'))
return render_template('myform.html', form=form)
@app.route('/success')
def success():
return "Form submitted successfully!"
if __name__ == '__main__':
app.run(debug=True)
1.5 Databases
1.5.1 Using Flask-SQLAlchemy
Installation:
pip install flask-sqlalchemy
Configuration:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
1.5.2 Define a Model
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
1.5.3 Create and Manage Tables
from yourapp import app, db
with app.app_context():
db.create_all() # Create tables
# In the Python shell:
# from yourapp import db, User, Post
# user_1 = User(username='Corey', email='corey@example.com')
# db.session.add(user_1)
# db.session.commit()
1.5.4 Querying the Database
from yourapp import db, User, Post
# Get all users
all_users = User.query.all()
# Filter users
filtered_users = User.query.filter_by(username='Corey')
# Get a single user by ID
user = User.query.get(1)
# Get a single user, handling 404 error
user = User.query.get_or_404(1)
# Create a new user
new_user = User(username='NewUser', email='new@example.com', password='password')
db.session.add(new_user)
db.session.commit()
# Update an existing user
user = User.query.get(1)
user.email = 'updated@example.com'
db.session.commit()
# Delete a user
user = User.query.get(1)
db.session.delete(user)
db.session.commit()
# Relationships
user = User.query.get(1)
posts = user.posts # Access posts related to the user
1.6 Static Files
1.6.1 Configure Static Files
Create a static
folder in your app directory.
In your template:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<img src="{% static 'images/logo.png' %}">
1.7 Blueprints
1.7.1 Create a Blueprint
from flask import Blueprint
main = Blueprint('main', __name__)
@main.route('/')
def index():
return "Main Blueprint Index"
1.7.2 Register a Blueprint
from flask import Flask
from yourapp.main import main
app = Flask(__name__)
app.register_blueprint(main)
1.8 Flask Extensions
1.8.1 Flask-Mail
Installation:
pip install flask-mail
Configuration:
from flask import Flask
from flask_mail import Mail, Message
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
app.config['MAIL_USERNAME'] = 'your_email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your_password'
mail = Mail(app)
Sending Emails:
from flask import Flask, render_template
from flask_mail import Mail, Message
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
app.config['MAIL_USERNAME'] = 'your_email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your_password'
mail = Mail(app)
@app.route('/send')
def send_email():
msg = Message("Hello",
sender="your_email@gmail.com",
recipients=["recipient@example.com"])
msg.body = "Hello Flask message sent from Flask-Mail"
mail.send(msg)
return "Sent"
1.8.2 Flask-Migrate
Installation:
pip install flask-migrate
Configuration:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
Migration Commands:
flask db init # Initialize the migration repository
flask db migrate -m "Initial migration" # Create a new migration
flask db upgrade # Apply the latest migration
flask db downgrade # Revert to a previous migration
1.8.3 Flask-Login
Installation:
pip install flask-login
Configuration:
from flask import Flask
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
login_manager = LoginManager(app)
login_manager.login_view = 'login' # Specify the login view
User Model:
from flask_login import UserMixin
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
# ... other fields ...
User Loader Callback:
from yourapp import login_manager, User
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
Protecting Views:
from flask_login import login_required
@app.route('/protected')
@login_required
def protected():
return "Protected View"
1.9 Testing
1.9.1 Using pytest
Installation:
pip install pytest pytest-flask
Test Example:
import pytest
from yourapp import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_index_route(client):
response = client.get('/')
assert response.status_code == 200
assert b'Hello, World!' in response.data
1.9.2 Using unittest
import unittest
from yourapp import app
class MyTestCase(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
self.app = app.test_client()
def test_index_route(self):
response = self.app.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Hello, World!', response.data)
1.10 Deployment
1.10.1 Production Settings
- Set
FLASK_ENV=production
to disable debug mode. - Use a production WSGI server (e.g., Gunicorn, uWSGI).
- Configure your web server (e.g., Nginx, Apache) to proxy requests to the WSGI server.
- Use a process manager (e.g., Supervisor, systemd) to manage the WSGI server.
- Configure logging.
- Use HTTPS.
1.10.2 WSGI Servers
Gunicorn:
pip install gunicorn
gunicorn yourapp:app --bind 0.0.0.0:8000
uWSGI:
pip install uwsgi
uwsgi --http 0.0.0.0:8000 --module yourapp
1.10.3 Environment Variables
Use environment variables for sensitive settings (e.g., SECRET_KEY
, database credentials).
1.10.4 Example Deployment with Gunicorn and Nginx
- Install Gunicorn:
pip install gunicorn
- Create a WSGI entry point:
yourapp.py
(already covered) - Create a systemd service file:
/etc/systemd/system/yourapp.service
[Unit]
Description=Gunicorn instance to serve yourapp
After=network.target
[Service]
User=youruser
Group=www-data
WorkingDirectory=/path/to/your/app
ExecStart=/path/to/your/venv/bin/gunicorn --workers 3 --max-requests 500 --bind unix:/run/yourapp.sock yourapp:app
[Install]
WantedBy=multi-user.target
- Create an Nginx configuration file:
/etc/nginx/sites-available/yourapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
include proxy_params;
proxy_pass http://unix:/run/yourapp.sock;
}
location /static {
alias /path/to/your/app/static;
}
}
- Create a symbolic link:
sudo ln -s /etc/nginx/sites-available/yourapp /etc/nginx/sites-enabled
- Restart Nginx:
sudo systemctl restart nginx
1.11 Security
- Use a strong
SECRET_KEY
and keep it secret. - Use HTTPS.
- Sanitize user input to prevent XSS attacks.
- Use parameterized queries to prevent SQL injection.
- Use a Content Security Policy (CSP) to prevent various attacks.
- Protect against CSRF attacks using Flask-WTF.
- Limit file upload sizes.
- Validate file uploads.
- Use a security linter (e.g., Bandit).
1.12 Logging
1.12.1 Configure Logging
import logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# In your code:
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
1.12.2 Logging to a File
import logging
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Create a file handler
log_handler = logging.handlers.RotatingFileHandler('yourapp.log', maxBytes=10240, backupCount=5)
log_handler.setLevel(logging.DEBUG)
# Create a logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log_handler.setFormatter(formatter)
# Add the handlers to the logger
logger.addHandler(log_handler)
1.13 Flask CLI
Flask provides a command-line interface for managing your application.
flask run
: Runs the development server.flask shell
: Opens a Python shell with the Flask application context.flask routes
: Shows the registered routes.flask db
: Manages database migrations (requires Flask-Migrate).
1.14 Context Processors
Context processors inject variables automatically into all templates.
from flask import Flask, render_template
app = Flask(__name__)
@app.context_processor
def inject_variables():
return dict(site_name="My Awesome Website")
@app.route('/')
def index():
return render_template('index.html')
In templates/index.html
:
<h1>Welcome to {{ site_name }}!</h1>
1.15 Error Handling
1.15.1 Custom Error Pages
from flask import Flask, render_template
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
1.15.2 Logging Exceptions
import logging
from flask import Flask, render_template
app = Flask(__name__)
logger = logging.getLogger(__name__)
@app.route('/')
def index():
try:
# Some code that might raise an exception
raise ValueError("Something went wrong")
except Exception as e:
logger.exception("An error occurred")
return render_template('error.html', error=str(e)), 500
1.16 Flask-RESTful
1.16.1 Installation
pip install flask-restful
1.16.2 Define Resources
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
1.16.3 Request Parsing
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('name', required=True, help="Name is required")
class MyResource(Resource):
def post(self):
args = parser.parse_args()
name = args['name']
return {'message': f'Hello, {name}!'}
1.17 Session Management
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
@app.route('/')
def index():
if 'username' in session:
return f'Logged in as {escape(session["username"])}
Click here to <a href="{url_for("logout")}">logout</a>'
return 'You are not logged in
Click here to <a href="{url_for("login")}">login</a>'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
1.18 Flask-CORS
1.18.1 Installation
pip install flask-cors
1.18.2 Usage
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
@app.route("/api/data")
def get_data():
return {"message": "This is CORS enabled!"}
1.19 Testing
1.19.1 Using pytest
Installation:
pip install pytest pytest-flask
Test Example:
import pytest
from yourapp import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_index_route(client):
response = client.get('/')
assert response.status_code == 200
assert b'Hello, World!' in response.data
1.19.2 Using unittest
import unittest
from yourapp import app
class MyTestCase(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
self.app = app.test_client()
def test_index_route(self):
response = self.app.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Hello, World!', response.data)
1.20 Deployment
1.20.1 Production Settings
- Set
FLASK_ENV=production
to disable debug mode. - Use a production WSGI server (e.g., Gunicorn, uWSGI).
- Configure your web server (e.g., Nginx, Apache) to proxy requests to the WSGI server.
- Use a process manager (e.g., Supervisor, systemd) to manage the WSGI server.
- Configure logging.
- Use HTTPS.
1.20.2 WSGI Servers
Gunicorn:
pip install gunicorn
gunicorn yourapp:app --bind 0.0.0.0:8000
uWSGI:
pip install uwsgi
uwsgi --http 0.0.0.0:8000 --module yourapp
1.20.3 Environment Variables
Use environment variables for sensitive settings (e.g., SECRET_KEY
, database credentials).
1.20.4 Example Deployment with Gunicorn and Nginx
- Install Gunicorn:
pip install gunicorn
- Create a WSGI entry point:
yourapp.py
(already covered) - Create a systemd service file:
/etc/systemd/system/yourapp.service
[Unit]
Description=Gunicorn instance to serve yourapp
After=network.target
[Service]
User=youruser
Group=www-data
WorkingDirectory=/path/to/your/app
ExecStart=/path/to/your/venv/bin/gunicorn --workers 3 --max-requests 500 --bind unix:/run/yourapp.sock yourapp:app
[Install]
WantedBy=multi-user.target
- Create an Nginx configuration file:
/etc/nginx/sites-available/yourapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
include proxy_params;
proxy_pass http://unix:/run/yourapp.sock;
}
location /static {
alias /path/to/your/app/static;
}
}
- Create a symbolic link:
sudo ln -s /etc/nginx/sites-available/yourapp /etc/nginx/sites-enabled
- Restart Nginx:
sudo systemctl restart nginx
1.21 Security
- Use a strong
SECRET_KEY
and keep it secret. - Use HTTPS.
- Sanitize user input to prevent XSS attacks.
- Use parameterized queries to prevent SQL injection.
- Use a Content Security Policy (CSP) to prevent various attacks.
- Protect against CSRF attacks using Flask-WTF.
- Limit file upload sizes.
- Validate file uploads.
- Use a security linter (e.g., Bandit).
1.22 Logging
1.22.1 Configure Logging
import logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# In your code:
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
1.22.2 Logging to a File
import logging
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Create a file handler
log_handler = logging.handlers.RotatingFileHandler('yourapp.log', maxBytes=10240, backupCount=5)
log_handler.setLevel(logging.DEBUG)
# Create a logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log_handler.setFormatter(formatter)
# Add the handlers to the logger
logger.addHandler(log_handler)
1.23 Flask CLI
Flask provides a command-line interface for managing your application.
flask run
: Runs the development server.flask shell
: Opens a Python shell with the Flask application context.flask routes
: Shows the registered routes.flask db
: Manages database migrations (requires Flask-Migrate).
To use the Flask CLI, you need to set the FLASK_APP
environment variable:
export FLASK_APP=yourapp.py
Then, you can use the flask
command:
flask run
1.24 Context Processors
Context processors inject variables automatically
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
@app.route("/api/data")
def get_data():
return {"message": "This is CORS enabled!"}
1.25 Testing
1.25.1 Using pytest
Installation:
pip install pytest pytest-flask
Test Example:
import pytest
from yourapp import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_index_route(client):
response = client.get('/')
assert response.status_code == 200
assert b'Hello, World!' in response.data
1.25.2 Using unittest
import unittest
from yourapp import app
class MyTestCase(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
self.app = app.test_client()
def test_index_route(self):
response = self.app.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Hello, World!', response.data)
1.26 Deployment
1.26.1 Production Settings
- Set
FLASK_ENV=production
to disable debug mode. - Use a production WSGI server (e.g., Gunicorn, uWSGI).
- Configure your web server (e.g., Nginx, Apache) to proxy requests to the WSGI server.
- Use a process manager (e.g., Supervisor, systemd) to manage the WSGI server.
- Configure logging.
- Use HTTPS.
1.26.2 WSGI Servers
Gunicorn:
pip install gunicorn
gunicorn yourapp:app --bind 0.0.0.0:8000
uWSGI:
pip install uwsgi
uwsgi --http 0.0.0.0:8000 --module yourapp
1.26.3 Environment Variables
Use environment variables for sensitive settings (e.g., SECRET_KEY
, database credentials).
1.26.4 Example Deployment with Gunicorn and Nginx
- Install Gunicorn:
pip install gunicorn
- Create a WSGI entry point:
yourapp.py
(already covered) - Create a systemd service file:
/etc/systemd/system/yourapp.service
[Unit]
Description=Gunicorn instance to serve yourapp
After=network.target
[Service]
User=youruser
Group=www-data
WorkingDirectory=/path/to/your/app
ExecStart=/path/to/your/venv/bin/gunicorn --workers 3 --max-requests 500 --bind unix:/run/yourapp.sock yourapp:app
[Install]
WantedBy=multi-user.target
- Create an Nginx configuration file:
/etc/nginx/sites-available/yourapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
include proxy_params;
proxy_pass http://unix:/run/yourapp.sock;
}
location /static {
alias /path/to/your/app/static;
}
}
- Create a symbolic link:
sudo ln -s /etc/nginx/sites-available/yourapp /etc/nginx/sites-enabled
- Restart Nginx:
sudo systemctl restart nginx
1.27 Security
- Use a strong
SECRET_KEY
and keep it secret. - Use HTTPS.
- Sanitize user input to prevent XSS attacks.
- Use parameterized queries to prevent SQL injection.
- Use a Content Security Policy (CSP) to prevent various attacks.
- Protect against CSRF attacks using Flask-WTF.
- Limit file upload sizes.
- Validate file uploads.
- Use a security linter (e.g., Bandit).
1.28 Logging
1.28.1 Configure Logging
import logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# In your code:
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
1.28.2 Logging to a File
import logging
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Create a file handler
log_handler = logging.handlers.RotatingFileHandler('yourapp.log', maxBytes=10240, backupCount=5)
log_handler.setLevel(logging.DEBUG)
# Create a logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log_handler.setFormatter(formatter)
# Add the handlers to the logger
logger.addHandler(log_handler)
1.29 Flask CLI
Flask provides a command-line interface for managing your application.
flask run
: Runs the development server.flask shell
: Opens a Python shell with the Flask application context.flask routes
: Shows the registered routes.flask db
: Manages database migrations (requires Flask-Migrate).
To use the Flask CLI, you need to set the FLASK_APP
environment variable:
export FLASK_APP=yourapp.py
Then, you can use the flask
command:
flask run
1.30 Context Processors
Context processors inject variables automatically into all templates.
from flask import Flask, render_template
app = Flask(__name__)
@app.context_processor
def inject_variables():
return dict(site_name="My Awesome Website")
@app.route('/')
def index():
return render_template('index.html')
In templates/index.html
:
<h1>Welcome to {{ site_name }}!</h1>
1.31 Error Handling
1.31.1 Custom Error Pages
from flask import Flask, render_template
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
1.31.2 Logging Exceptions
import logging
from flask import Flask, render_template
app = Flask(__name__)
logger = logging.getLogger(__name__)
@app.route('/')
def index():
try:
# Some code that might raise an exception
raise ValueError("Something went wrong")
except Exception as e:
logger.exception("An error occurred")
return render_template('error.html', error=str(e)), 500
1.32 Flask-RESTful
1.32.1 Installation
pip install flask-restful
1.32.2 Define Resources
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
1.32.3 Request Parsing
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('name', required=True, help="Name is required")
class MyResource(Resource):
def post(self):
args = parser.parse_args()
name = args['name']
return {'message': f'Hello, {name}!'}
1.33 Session Management
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
@app.route('/')
def index():
if 'username' in session:
return f'Logged in as {escape(session["username"])}
Click here to <a href="{url_for("logout")}">logout</a>'
return 'You are not logged in
Click here to <a href="{url_for("login")}">login</a>'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
1.34 Flask-CORS
1.34.1 Installation
pip install flask-cors
1.34.2 Usage
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
@app.route("/api/data")
def get_data():
return {"message": "This is CORS enabled!"}
1.35 Signals
Flask doesn't have built-in signals like Django, but you can use a third-party library like blinker
to implement signals.
1.35.1 Installation
pip install blinker
1.35.2 Usage
from flask import Flask
from blinker import signal
app = Flask(__name__)
before_request = signal('before_request')
@app.before_request
def before_request_handler():
before_request.send(app)
@before_request.connect
def my_listener(sender):
print("Before request signal received")
@app.route('/')
def index():
return "Hello, World!"
1.36 Flask-Limiter
1.36.1 Installation
pip install Flask-Limiter
1.36.2 Usage
from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.route("/slow")
@limiter.limit("10 per minute")
def slow():
return "Slow route"
@app.route("/fast")
def fast():
return "Fast route"
1.37 Flask-APScheduler
1.37.1 Installation
pip install flask-apscheduler
1.37.2 Usage
from flask import Flask
from flask_apscheduler import APScheduler
import time
class Config(object):
JOBS = [
{
'id': 'job1',
'func': 'yourapp:job1',
'trigger': 'interval',
'seconds': 10
}
]
SCHEDULER_API_ENABLED = True
app = Flask(__name__)
app.config.from_object(Config())
scheduler = APScheduler()
# it is also possible to enable the API directly
# scheduler.api_enabled = True
scheduler.init_app(app)
scheduler.start()
def job1():
print(time.strftime("%Y-%m-%d %H:%M:%S"))
if __name__ == '__main__':
app.run(debug=True)
1.38 Flask-Sitemap
1.38.1 Installation
pip install Flask-Sitemap
1.38.2 Usage
from flask import Flask
from flask_sitemap import Sitemap
app = Flask(__name__)
ext = Sitemap(app=app)
@app.route("/sitemap.xml")
def sitemap():
return ext.generate(base_url='http://example.com')
1.39 Flask-WTF CSRF Protection
1.39.1 Configuration
from flask import Flask
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
csrf = CSRFProtect(app)
1.39.2 Usage in Templates
<form method="post">
{{ form.csrf_token }}
<!-- Your form fields -->
</form>
1.40 Flask-FlatPages
1.40.1 Installation
pip install Flask-FlatPages
1.40.2 Configuration
from flask import Flask
from flask_flatpages import FlatPages
app = Flask(__name__)
app.config['FLATPAGES_EXTENSION'] = '.md'
app.config['FLATPAGES_ROOT'] = 'pages'
pages = FlatPages(app)
1.40.3 Usage
Create a directory named pages
in your project root. Add your flat pages as .md
files.
from flask import Flask, render_template
from flask_flatpages import FlatPages, pygments_style_defs
app = Flask(__name__)
app.config['FLATPAGES_EXTENSION'] = '.md'
app.config['FLATPAGES_ROOT'] = 'pages'
app.config['FLATPAGES_MARKDOWN_EXTENSIONS'] = ['codehilite', 'fenced_code']
app.config['PYGMENTS_STYLE'] = 'default'
pages = FlatPages(app)
@app.route('/page/<path:path>')
def page(path):
page = pages.get_or_404(path)
return render_template('page.html', page=page, pygments_style=pygments_style_defs())
1.41 Flask-Assets
1.41.1 Installation
pip install Flask-Assets
1.41.2 Configuration
from flask import Flask
from flask_assets import Environment, Bundle
app = Flask(__name__)
assets = Environment(app)
js = Bundle('js/jquery.js', 'js/base.js', filters='jsmin', output='gen/packed.js')
css = Bundle('css/base.css', 'css/common.css', filters='cssmin', output='gen/all.css')
assets.register('all_js', js)
assets.register('all_css', css)
1.41.3 Usage in Templates
{% assets "all_js" %}
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}
{% assets "all_css" %}
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
{% endassets %}
1.42 Flask-Babel
1.42.1 Installation
pip install Flask-Babel
1.42.2 Configuration
from flask import Flask
from flask_babel import Babel
app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
babel = Babel(app)
1.42.3 Usage
from flask import Flask, render_template
from flask_babel import Babel, gettext
app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
babel = Babel(app)
@app.route('/')
def index():
title = gettext('Welcome')
return render_template('index.html', title=title)
In templates/index.html
:
<h1>{{ title }}</h1>
1.43 Flask-SocketIO
1.43.1 Installation
pip install flask-socketio
1.43.2 Usage
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
@app.route('/')
def index():
return render_template('index.html')
@socketio.on('connect')
def test_connect():
emit('my response', {'data': 'Connected!'})
@socketio.on('my event')
def handle_my_custom_event(json):
print('received json: ' + str(json))
socketio.emit('my response', json)
if __name__ == '__main__':
socketio.run(app, debug=True)
In templates/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Flask-SocketIO Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWj3kcmNeAqFvv3EY9JJ/KEvVcjtgJBmWsGGHa+YwdlOfjoOvozUvCpJlPzl5lwCDsLQIY9Mq1v8XtZiuCQ==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var socket = io();
socket.on('connect', function() {
socket.emit('my event', {data: 'I\'m connected!'});
});
socket.on('my response', function(msg) {
$('#log').append('<p>Received: ' + msg.data + '</p>');
});
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
});
</script>
</head>
<body>
<h1>Flask-SocketIO Test</h1>
<div id="log"></div>
<form id="emit" method="POST" action="#">
<input type="text" id="emit_data" name="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
</body>
</html>
1.44 Flask-Principal
1.44.1 Installation
pip install Flask-Principal
1.44.2 Usage
from flask import Flask, g
from flask_principal import Principal, Permission, RoleNeed, UserNeed, identity_loaded, UserContext, Identity, AnonymousIdentity
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
principals = Principal(app)
# Define Needs
admin_permission = Permission(RoleNeed('admin'))
poster_permission = Permission(RoleNeed('poster'))
# Define Roles
admin_role = RoleNeed('admin')
poster_role = RoleNeed('poster')
user_need = UserNeed(1)
@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
# Set the identity user object
identity.user = get_user()
# Add the UserNeed to the identity
identity.provides.add(UserNeed(identity.user.id))
# Assuming the user has a method that returns a list of roles
for role in identity.user.roles:
identity.provides.add(RoleNeed(role.name))
def get_user():
# Replace with your user loading logic (e.g., from database)
class User(object):
def __init__(self, id, roles):
self.id = id
self.roles = roles
class Role(object):
def __init__(self, name):
self.name = name
admin_role = Role('admin')
poster_role = Role('poster')
user = User(1, [admin_role, poster_role])
return user
@app.route('/')
def index():
with UserContext(Identity(1)):
if admin_permission.can():
return "Admin access granted"
elif poster_permission.can():
return "Poster access granted"
else:
return "Access denied"
if __name__ == '__main__':
app.run(debug=True)
1.45 Flask-JWT-Extended
1.45.1 Installation
pip install Flask-JWT-Extended
1.45.2 Usage
from flask import Flask
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "super-secret" # Change this!
jwt = JWTManager(app)
@app.route("/login", methods=["POST"])
def login():
username = request.json.get("username", None)
password = request.json.get("password", None)
if username != "test" or password != "test":
return jsonify({"msg": "Bad username or password"}), 401
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token)
@app.route("/protected", methods=["GET"])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
1.46 Flask-Uploads
1.46.1 Installation
pip install Flask-Uploads
1.46.2 Usage
from flask import Flask, request, render_template
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
app = Flask(__name__)
app.config['UPLOADED_PHOTOS_DEST'] = 'uploads'
app.config['SECRET_KEY'] = 'super secret key'
photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app) # set maximum file size, default is 16MB
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and 'photo' in request.files:
filename = photos.save(request.files['photo'])
url = photos.url(filename)
return render_template('upload.html', filename=filename, url=url)
return render_template('upload.html')
In templates/upload.html
:
<!doctype html>
<html>
<head>
<title>Upload</title>
</head>
<body>
{% if filename %}
<img src="{{ url }}" alt="Uploaded Image">
{% else %}
<form method="post" enctype="multipart/form-data">
<input type="file" name="photo">
<button type="submit">Upload</button>
</form>
{% endif %}
</body>
</html>
1.47 Flask-Mail
1.47.1 Installation
pip install flask-mail
1.47.2 Configuration
from flask import Flask
from flask_mail import Mail, Message
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
app.config['MAIL_USERNAME'] = 'your_email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your_password'
mail = Mail(app)
1.47.3 Sending Emails
from flask import Flask, render_template
from flask_mail import Mail, Message
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
app.config['MAIL_USERNAME'] = 'your_email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your_password'
mail = Mail(app)
@app.route('/send')
def send_email():
msg = Message("Hello",
sender="your_email@gmail.com",
recipients=["recipient@example.com"])
msg.body = "Hello Flask message sent from Flask-Mail"
mail.send(msg)
return "Sent"
1.48 Flask-APScheduler
1.48.1 Installation
pip install flask-apscheduler
1.48.2 Usage
from flask import Flask
from flask_apscheduler import APScheduler
import time
class Config(object):
JOBS = [
{
'id': 'job1',
'func': 'yourapp:job1',
'trigger': 'interval',
'seconds': 10
}
]
SCHEDULER_API_ENABLED = True
app = Flask(__name__)
app.config.from_object(Config())
scheduler = APScheduler()
# it is also possible to enable the API directly
# scheduler.api_enabled = True
scheduler.init_app(app)
scheduler.start()
def job1():
print(time.strftime("%Y-%m-%d %H:%M:%S"))
if __name__ == '__main__':
app.run(debug=True)
1.49 Flask-Sitemap
1.49.1 Installation
pip install Flask-Sitemap
1.49.2 Usage
from flask import Flask
from flask_sitemap import Sitemap
app = Flask(__name__)
ext = Sitemap(app=app)
@app.route("/sitemap.xml")
def sitemap():
return ext.generate(base_url='http://example.com')
1.50 Flask-WTF CSRF Protection
1.50.1 Configuration
from flask import Flask
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
csrf = CSRFProtect(app)
1.50.2 Usage in Templates
<form method="post">
{{ form.csrf_token }}
<!-- Your form fields -->
</form>
1.51 Tips and Best Practices
- Use virtual environments to isolate project dependencies.
- Keep
SECRET_KEY
secure and out of your codebase. Use environment variables. - Use meaningful names for routes, variables, and functions.
- Follow the DRY (Don't Repeat Yourself) principle.
- Write unit tests to ensure code quality.
- Use a production-ready web server (e.g., Gunicorn, uWSGI) and a process manager (e.g., Supervisor, systemd) for deployment.
- Use a linter (like
flake8
) and formatter (likeblack
) to ensure consistent code style. - Keep your code modular and reusable.
- Document your code.
- Use a version control system (e.g., Git).
- Follow Flask's coding style guidelines.
- Use Flask's built-in session management or a more robust solution like Flask-Session.
- Monitor your application for errors and performance issues.
- Use a CDN (Content Delivery Network) for static files.
- Optimize database queries.
- Use asynchronous tasks for long-running operations (e.g., sending emails) using Celery or similar.
- Implement proper logging and error handling.
- Regularly update Flask and its dependencies.
- Use a security scanner to identify potential vulnerabilities.
- Follow security best practices.
- Use a reverse proxy like Nginx or Apache in front of your WSGI server.
- Use a load balancer for high availability.
- Automate deployments using tools like Fabric or Ansible.
- Use a monitoring tool like Sentry or New Relic.
- Implement health checks for your application.
- Use a CDN for static assets.
- Cache frequently accessed data.
- Use a database connection pool.
- Optimize your database queries.
- Use a task queue for long-running tasks.
- Use a background worker for asynchronous tasks.
- Use a message queue for inter-process communication.
- Use a service discovery tool for microservices.
- Use a containerization tool like Docker.
- Use an orchestration tool like Kubernetes.