1 #1

Closed
pnymz6gv8 wants to merge 0 commits from master into main

@ -1,2 +0,0 @@
# packets14

Binary file not shown.

@ -0,0 +1,153 @@
# Flask
from flask import Flask, render_template_string, request, redirect, url_for, session, jsonify, flash, g
app = Flask(__name__)
app.secret_key = 'demo_secret_key_for_testing'
# 模拟数据库
users = {}
messages = []
# 首页模板
HOME_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head>
<title>Flask 示例应用</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.flash { padding: 10px; margin: 10px 0; background: #d4edda; border-radius: 5px; }
.message { padding: 10px; margin: 5px 0; background: #f8f9fa; border-radius: 5px; }
form { margin: 20px 0; }
input, button { padding: 10px; margin: 5px; }
</style>
</head>
<body>
<h1>Flask 示例应用</h1>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% if session.get('username') %}
<p>欢迎, {{ session['username'] }}! <a href="{{ url_for('logout') }}">退出</a></p>
{% else %}
<p><a href="{{ url_for('login') }}">登录</a> | <a href="{{ url_for('register') }}">注册</a></p>
{% endif %}
<h2>留言板</h2>
<form method="POST" action="{{ url_for('add_message') }}">
<input type="text" name="content" placeholder="输入留言..." required>
<button type="submit">发送</button>
</form>
<h3>所有留言:</h3>
{% for msg in messages %}
<div class="message"><strong>{{ msg.user }}:</strong> {{ msg.content }}</div>
{% endfor %}
<hr>
<p><a href="{{ url_for('api_info') }}">API 信息 (JSON)</a></p>
</body>
</html>
'''
LOGIN_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head><title>登录</title></head>
<body>
<h1>登录</h1>
<form method="POST">
<input type="text" name="username" placeholder="用户名" required><br><br>
<input type="password" name="password" placeholder="密码" required><br><br>
<button type="submit">登录</button>
</form>
<p><a href="{{ url_for('index') }}">返回首页</a></p>
</body>
</html>
'''
REGISTER_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head><title>注册</title></head>
<body>
<h1>注册</h1>
<form method="POST">
<input type="text" name="username" placeholder="用户名" required><br><br>
<input type="password" name="password" placeholder="密码" required><br><br>
<button type="submit">注册</button>
</form>
<p><a href="{{ url_for('index') }}">返回首页</a></p>
</body>
</html>
'''
@app.before_request
def before_request():
"""请求前钩子 - 记录请求信息"""
g.request_start = 'Request started'
@app.route('/')
def index():
"""首页路由"""
return render_template_string(HOME_TEMPLATE, messages=messages)
@app.route('/login', methods=['GET', 'POST'])
def login():
"""登录路由"""
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username in users and users[username] == password:
session['username'] = username
flash('登录成功!')
return redirect(url_for('index'))
flash('用户名或密码错误!')
return render_template_string(LOGIN_TEMPLATE)
@app.route('/register', methods=['GET', 'POST'])
def register():
"""注册路由"""
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username in users:
flash('用户名已存在!')
else:
users[username] = password
flash('注册成功,请登录!')
return redirect(url_for('login'))
return render_template_string(REGISTER_TEMPLATE)
@app.route('/logout')
def logout():
"""退出登录"""
session.pop('username', None)
flash('已退出登录')
return redirect(url_for('index'))
@app.route('/message', methods=['POST'])
def add_message():
"""添加留言"""
content = request.form.get('content', '')
username = session.get('username', '匿名用户')
if content:
messages.append({'user': username, 'content': content})
return redirect(url_for('index'))
@app.route('/api/info')
def api_info():
"""API 接口 - 返回 JSON 数据"""
return jsonify({
'app_name': 'Flask Demo',
'version': '1.0',
'total_users': len(users),
'total_messages': len(messages)
})
if __name__ == '__main__':
print("Flask 示例应用")
print("运行命令: flask run 或 python demo_app.py")
print("访问地址: http://127.0.0.1:5000")
app.run(debug=True)

@ -0,0 +1,17 @@
{
"name": "pallets/flask",
"image": "mcr.microsoft.com/devcontainers/python:3",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "${workspaceFolder}/.venv",
"python.terminal.activateEnvInCurrentTerminal": true,
"python.terminal.launchArgs": [
"-X",
"dev"
]
}
}
},
"onCreateCommand": ".devcontainer/on-create-command.sh"
}

@ -0,0 +1,7 @@
#!/bin/bash
set -e
python3 -m venv --upgrade-deps .venv
. .venv/bin/activate
pip install -r requirements/dev.txt
pip install -e .
pre-commit install --install-hooks

@ -0,0 +1,13 @@
root = true
[*]
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
max_line_length = 88
[*.{css,html,js,json,jsx,scss,ts,tsx,yaml,yml}]
indent_size = 2

@ -0,0 +1,8 @@
.idea/
.vscode/
__pycache__/
dist/
.coverage*
htmlcov/
.tox/
docs/_build/

@ -0,0 +1,18 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 488940d9de1b658fac229e34c521d75a6ea476f2 # frozen: v0.14.5
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/astral-sh/uv-pre-commit
rev: b6675a113e27a9b18f3d60c05794d62ca80c7ab5 # frozen: 0.9.9
hooks:
- id: uv-lock
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-merge-conflict
- id: debug-statements
- id: fix-byte-order-marker
- id: trailing-whitespace
- id: end-of-file-fixer

@ -0,0 +1,10 @@
version: 2
build:
os: ubuntu-24.04
tools:
python: '3.13'
commands:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
- uv run --group docs sphinx-build -W -b dirhtml docs $READTHEDOCS_OUTPUT/html

File diff suppressed because it is too large Load Diff

@ -0,0 +1,28 @@
Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,53 @@
<div align="center"><img src="https://raw.githubusercontent.com/pallets/flask/refs/heads/stable/docs/_static/flask-name.svg" alt="" height="150"></div>
# Flask
Flask is a lightweight [WSGI] web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around [Werkzeug]
and [Jinja], and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
[WSGI]: https://wsgi.readthedocs.io/
[Werkzeug]: https://werkzeug.palletsprojects.com/
[Jinja]: https://jinja.palletsprojects.com/
## A Simple Example
```python
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
```
```
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
## Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, [please
donate today].
[please donate today]: https://palletsprojects.com/donate
## Contributing
See our [detailed contributing documentation][contrib] for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
[contrib]: https://palletsprojects.com/contributing/

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="Icon" x="0" y="0" width="500" height="500" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="0" y="0" width="500" height="500"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g>
<path d="M224.446,59.975c-0.056,-4.151 -0.483,-5.543 -2.7,-6.823c-2.104,-1.393 -5.288,-1.421 -8.329,-0.085l-204.674,87.64c-3.042,1.336 -5.913,4.008 -7.448,6.908c-1.535,2.899 -1.705,5.97 -0.511,8.158l17.084,31.384l0.228,0.369c1.847,2.928 6.026,3.696 10.29,1.82l1.251,-0.54c5.344,22.4 14.1,50.429 25.783,70.413l178.294,-79.794c-2.559,-23.14 -9.552,-89.602 -9.268,-119.479l0,0.029Z" style="fill:#3babc3;fill-rule:nonzero;"/>
<path d="M238.603,205.776l-171.698,76.838c10.091,19.132 22.542,39.428 37.722,58.986c50.429,-25.698 100.887,-51.396 151.316,-77.094c-3.269,-8.471 -6.452,-17.653 -17.34,-58.73Z" style="fill:#3babc3;fill-rule:nonzero;"/>
<path d="M497.601,388.846l-12.139,-18.535c-1.819,-2.018 -4.633,-2.786 -7.106,-1.791l-15.578,5.999c-1.848,-2.047 -4.52,-2.815 -7.135,-1.791c-5.089,1.99 -10.206,4.008 -15.294,5.998c-1.649,0.625 -2.104,1.847 -1.791,3.439l0.995,4.861c-28.711,3.099 -77.236,1.564 -120.701,-32.577c-19.216,-15.066 -37.239,-36.386 -52.277,-66.206l-144.75,73.768c26.466,29.08 59.697,54.864 100.973,70.385c57.422,21.633 130.593,23.679 222.838,-13.475l0.512,2.616c0.455,2.928 3.98,6.026 8.755,4.15l15.323,-5.97c5.258,-1.99 5.287,-6.026 4.519,-8.641l19.729,-7.704c2.217,-0.853 9.096,-6.169 3.183,-14.526l-0.056,-0Z" style="fill:#3babc3;fill-rule:nonzero;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="Logo" x="0" y="0" width="500" height="500" style="fill:none;"/>
<g>
<path id="Box" d="M500,50l0,400c0,27.596 -22.404,50 -50,50l-400,0c-27.596,0 -50,-22.404 -50,-50l0,-400c0,-27.596 22.404,-50 50,-50l400,0c27.596,0 50,22.404 50,50Z" style="fill:url(#_Linear1);"/>
<path id="Shadow" d="M500,398.646l0,51.354c0,27.596 -22.404,50 -50,50l-94.111,0l-170.452,-170.451c13.541,12.279 29.511,22.845 48.242,29.888c34.453,12.98 78.356,14.208 133.703,-8.084l0.307,1.569c0.273,1.757 2.388,3.616 5.253,2.49l9.193,-3.582c3.156,-1.194 3.173,-3.616 2.712,-5.185l11.837,-4.622c1.331,-0.512 5.458,-3.701 1.91,-8.716l-0.034,0l-7.283,-11.12c-1.091,-1.211 -2.78,-1.672 -4.264,-1.075l-9.346,3.599c-1.109,-1.228 -2.712,-1.688 -4.281,-1.074c-3.054,1.194 -6.124,2.404 -9.177,3.598c-0.989,0.376 -1.262,1.109 -1.074,2.064l0.597,2.917c-17.227,1.859 -46.342,0.938 -72.421,-19.547c-11.53,-9.039 -22.343,-21.831 -31.366,-39.723l-83.923,42.769l-13.246,-10.755c30.258,-15.419 60.532,-30.837 90.79,-46.256c-1.961,-5.083 -3.872,-10.592 -10.404,-35.238l-98.082,43.893l-11.828,-11.828l106.976,-47.876c-1.534,-13.88 -5.728,-53.736 -5.56,-71.67l-0,-0.017c-0.027,-1.894 -0.184,-2.827 -0.85,-3.504l266.182,266.182Zm-388.562,-185.436c1.272,1.164 3.414,1.356 5.594,0.397l0.75,-0.324c0.645,2.703 1.373,5.543 2.181,8.452l-8.525,-8.525Z" style="fill:#3b808b;"/>
<g id="Icon">
<path d="M234.668,135.985c-0.034,-2.49 -0.29,-3.326 -1.62,-4.094c-1.263,-0.835 -3.173,-0.852 -4.998,-0.051l-122.804,52.584c-1.825,0.802 -3.548,2.405 -4.469,4.145c-0.921,1.74 -1.023,3.582 -0.307,4.895l10.251,18.83l0.136,0.222c1.109,1.757 3.616,2.217 6.175,1.091l0.75,-0.324c3.207,13.441 8.46,30.258 15.47,42.248l106.976,-47.876c-1.535,-13.884 -5.731,-53.761 -5.56,-71.687l-0,0.017Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M243.162,223.466l-103.019,46.103c6.055,11.478 13.525,23.656 22.633,35.391c30.258,-15.419 60.532,-30.837 90.79,-46.256c-1.961,-5.083 -3.872,-10.592 -10.404,-35.238Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M398.56,333.307l-7.283,-11.12c-1.091,-1.211 -2.78,-1.672 -4.264,-1.075l-9.346,3.599c-1.109,-1.228 -2.712,-1.688 -4.281,-1.074c-3.054,1.194 -6.124,2.404 -9.177,3.598c-0.989,0.376 -1.262,1.109 -1.074,2.064l0.597,2.917c-17.227,1.859 -46.342,0.938 -72.421,-19.547c-11.53,-9.039 -22.343,-21.831 -31.366,-39.723l-86.85,44.26c15.879,17.449 35.818,32.919 60.584,42.231c34.453,12.98 78.356,14.208 133.703,-8.084l0.307,1.569c0.273,1.757 2.388,3.616 5.253,2.49l9.193,-3.582c3.156,-1.194 3.173,-3.616 2.712,-5.185l11.837,-4.622c1.331,-0.512 5.458,-3.701 1.91,-8.716l-0.034,0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(3.06162e-14,500,-500,3.06162e-14,267.59,0)"><stop offset="0" style="stop-color:#bdddeb;stop-opacity:1"/><stop offset="1" style="stop-color:#53a9d1;stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 706 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path id="Name" d="M420.35,117.6l-37.65,-0c-4.4,-0 -7.475,0.85 -9.225,2.55c-1.75,1.7 -2.625,4.65 -2.625,8.85l-0,14.85l39.15,-0l-1.5,18.6l-37.65,-0l-0,43.35l-20.85,-0l-0,-85.05c-0,-7.9 1.725,-13.5 5.175,-16.8c3.45,-3.3 9.375,-4.95 17.775,-4.95l47.4,-0l0,18.6Z" style="fill-rule:nonzero;"/>
<path d="M455.75,205.8l-19.5,0.15l-0,-112.95l19.5,-0l-0,112.8Z" style="fill-rule:nonzero;"/>
<path d="M535.7,205.8l-13.05,-0l-6,-10.35l-20.85,11.25c-11.6,-0 -19.4,-4.2 -23.4,-12.6c-2,-4.1 -3.375,-8.525 -4.125,-13.275c-0.75,-4.75 -1.125,-9.7 -1.125,-14.85c-0,-5.15 0.05,-8.95 0.15,-11.4c0.1,-2.45 0.35,-5.3 0.75,-8.55c0.4,-3.25 0.975,-5.975 1.725,-8.175c0.75,-2.2 1.825,-4.475 3.225,-6.825c1.4,-2.35 3.1,-4.225 5.1,-5.625c4.5,-3.1 10.35,-4.65 17.55,-4.65l20.55,-0l19.5,-1.2l-0,86.25Zm-19.5,-27.3l-0,-40.2l-14.85,-0c-5.5,-0 -9.325,2.1 -11.475,6.3c-2.15,4.2 -3.225,10.475 -3.225,18.825c-0,8.35 1.025,14.225 3.075,17.625c2.05,3.4 5.925,5.1 11.625,5.1l14.85,-7.65Z" style="fill-rule:nonzero;"/>
<path d="M615.65,182.1l0,2.25c-0.6,7.5 -3.775,13.15 -9.525,16.95c-5.75,3.8 -12.925,5.7 -21.525,5.7c-12.7,-0 -21.6,-2.3 -26.7,-6.9c-4.7,-4.2 -7.05,-10.4 -7.05,-18.6l0,-1.8l17.7,0c0,4.6 1.2,7.75 3.6,9.45c2.4,1.7 6.55,2.55 12.45,2.55c8,0 12,-2.9 12,-8.7c0,-4.8 -1.4,-8 -4.2,-9.6c-1.3,-0.8 -2.95,-1.4 -4.95,-1.8l-15.15,-2.55c-13.2,-2.1 -19.8,-10.35 -19.8,-24.75c0,-8 2.925,-14.225 8.775,-18.675c5.85,-4.45 13.275,-6.675 22.275,-6.675c20.5,0 30.75,8.85 30.75,26.55l0,1.95l-16.95,0c-0.2,-4.7 -1.45,-7.9 -3.75,-9.6c-2.3,-1.7 -5.525,-2.55 -9.675,-2.55c-4.15,0 -7.275,0.825 -9.375,2.475c-2.1,1.65 -3.15,3.475 -3.15,5.475c0,5.7 2.3,8.95 6.9,9.75l18.15,3.3c12.8,2.4 19.2,11 19.2,25.8Z" style="fill-rule:nonzero;"/>
<path d="M705.65,205.8l-23.4,-0l-22.5,-30.3l-8.55,12.15l0,18.15l-19.5,-0l0,-112.8l19.5,-0l0,71.25l27.3,-40.65l22.05,-0l-28.05,38.4l33.15,43.8Z" style="fill-rule:nonzero;"/>
<g id="Logo">
<path id="Box" d="M300,30l0,240c0,16.557 -13.443,30 -30,30l-240,-0c-16.557,-0 -30,-13.443 -30,-30l0,-240c0,-16.557 13.443,-30 30,-30l240,0c16.557,0 30,13.443 30,30Z" style="fill:url(#_Linear1);"/>
<path id="Shadow" d="M300,239.188l0,30.812c0,16.557 -13.443,30 -30,30l-56.467,-0l-102.271,-102.271c8.125,7.368 17.707,13.707 28.945,17.933c20.672,7.788 47.014,8.525 80.222,-4.85l0.184,0.941c0.164,1.054 1.433,2.17 3.152,1.494l5.516,-2.149c1.893,-0.716 1.904,-2.169 1.627,-3.111l7.103,-2.773c0.798,-0.307 3.274,-2.221 1.146,-5.23l-0.021,0l-4.37,-6.672c-0.655,-0.727 -1.668,-1.003 -2.558,-0.645l-5.608,2.16c-0.665,-0.737 -1.627,-1.013 -2.569,-0.645c-1.832,0.716 -3.674,1.443 -5.505,2.159c-0.594,0.225 -0.758,0.665 -0.645,1.239l0.358,1.749c-10.336,1.116 -27.805,0.563 -43.452,-11.727c-6.918,-5.424 -13.406,-13.099 -18.82,-23.835l-50.354,25.662l-7.947,-6.453c18.154,-9.251 36.319,-18.502 54.474,-27.754c-1.177,-3.049 -2.323,-6.355 -6.243,-21.143l-58.849,26.336l-7.097,-7.096l64.186,-28.726c-0.921,-8.328 -3.437,-32.242 -3.336,-43.002l-0,-0.01c-0.016,-1.137 -0.111,-1.697 -0.51,-2.103l159.709,159.71Zm-233.137,-111.262c0.763,0.699 2.048,0.814 3.356,0.238l0.45,-0.194c0.387,1.622 0.824,3.325 1.309,5.071l-5.115,-5.115Z" style="fill:#3b808b;"/>
<g id="Icon">
<path d="M140.801,81.591c-0.021,-1.494 -0.174,-1.996 -0.972,-2.456c-0.758,-0.502 -1.904,-0.512 -2.999,-0.031l-73.683,31.551c-1.095,0.481 -2.128,1.443 -2.681,2.486c-0.552,1.044 -0.614,2.149 -0.184,2.937l6.151,11.298l0.081,0.133c0.666,1.055 2.17,1.331 3.705,0.655l0.45,-0.194c1.924,8.064 5.076,18.155 9.282,25.349l64.186,-28.726c-0.921,-8.33 -3.439,-32.257 -3.336,-43.012l-0,0.01Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M145.897,134.079l-61.811,27.662c3.633,6.887 8.115,14.194 13.58,21.235c18.154,-9.251 36.319,-18.502 54.474,-27.754c-1.177,-3.049 -2.323,-6.355 -6.243,-21.143Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M239.136,199.984l-4.37,-6.672c-0.655,-0.727 -1.668,-1.003 -2.558,-0.645l-5.608,2.16c-0.665,-0.737 -1.627,-1.013 -2.569,-0.645c-1.832,0.716 -3.674,1.443 -5.505,2.159c-0.594,0.225 -0.758,0.665 -0.645,1.239l0.358,1.749c-10.336,1.116 -27.805,0.563 -43.452,-11.727c-6.918,-5.424 -13.406,-13.099 -18.82,-23.835l-52.11,26.557c9.528,10.469 21.491,19.751 36.35,25.338c20.672,7.788 47.014,8.525 80.222,-4.85l0.184,0.941c0.164,1.054 1.433,2.17 3.152,1.494l5.516,-2.149c1.893,-0.716 1.904,-2.169 1.627,-3.111l7.103,-2.773c0.798,-0.307 3.274,-2.221 1.146,-5.23l-0.021,0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.83697e-14,300,-300,1.83697e-14,160.554,0)"><stop offset="0" style="stop-color:#bdddeb;stop-opacity:1"/><stop offset="1" style="stop-color:#53a9d1;stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

@ -0,0 +1,708 @@
API
===
.. module:: flask
This part of the documentation covers all the interfaces of Flask. For
parts where Flask depends on external libraries, we document the most
important right here and provide links to the canonical documentation.
Application Object
------------------
.. autoclass:: Flask
:members:
:inherited-members:
Blueprint Objects
-----------------
.. autoclass:: Blueprint
:members:
:inherited-members:
Incoming Request Data
---------------------
.. autoclass:: Request
:members:
:inherited-members:
:exclude-members: json_module
.. data:: request
A proxy to the request data for the current request, an instance of
:class:`.Request`.
This is only available when a :doc:`request context </appcontext>` is
active.
This is a proxy. See :ref:`context-visibility` for more information.
Response Objects
----------------
.. autoclass:: flask.Response
:members:
:inherited-members:
:exclude-members: json_module
Sessions
--------
If you have set :attr:`Flask.secret_key` (or configured it from
:data:`SECRET_KEY`) you can use sessions in Flask applications. A session makes
it possible to remember information from one request to another. The way Flask
does this is by using a signed cookie. The user can look at the session
contents, but can't modify it unless they know the secret key, so make sure to
set that to something complex and unguessable.
To access the current session you can use the :data:`.session` proxy.
.. data:: session
A proxy to the session data for the current request, an instance of
:class:`.SessionMixin`.
This is only available when a :doc:`request context </appcontext>` is
active.
This is a proxy. See :ref:`context-visibility` for more information.
The session object works like a dict but tracks assignment and access to its
keys. It cannot track modifications to mutable values, you need to set
:attr:`~.SessionMixin.modified` manually when modifying a list, dict, etc.
.. code-block:: python
# appending to a list is not detected
session["numbers"].append(42)
# so mark it as modified yourself
session.modified = True
The session is persisted across requests using a cookie. By default the
users's browser will clear the cookie when it is closed. Set
:attr:`~.SessionMixin.permanent` to ``True`` to persist the cookie for
:data:`PERMANENT_SESSION_LIFETIME`.
Session Interface
-----------------
.. versionadded:: 0.8
The session interface provides a simple way to replace the session
implementation that Flask is using.
.. currentmodule:: flask.sessions
.. autoclass:: SessionInterface
:members:
.. autoclass:: SecureCookieSessionInterface
:members:
.. autoclass:: SecureCookieSession
:members:
.. autoclass:: NullSession
:members:
.. autoclass:: SessionMixin
:members:
.. admonition:: Notice
The :data:`PERMANENT_SESSION_LIFETIME` config can be an integer or ``timedelta``.
The :attr:`~flask.Flask.permanent_session_lifetime` attribute is always a
``timedelta``.
Test Client
-----------
.. currentmodule:: flask.testing
.. autoclass:: FlaskClient
:members:
Test CLI Runner
---------------
.. currentmodule:: flask.testing
.. autoclass:: FlaskCliRunner
:members:
Application Globals
-------------------
.. currentmodule:: flask
To share data that is valid for one request only from one function to
another, a global variable is not good enough because it would break in
threaded environments. Flask provides you with a special object that
ensures it is only valid for the active request and that will return
different values for each request. In a nutshell: it does the right
thing, like it does for :data:`.request` and :data:`.session`.
.. data:: g
A proxy to a namespace object used to store data during a single request or
app context. An instance of :attr:`.Flask.app_ctx_globals_class`, which
defaults to :class:`._AppCtxGlobals`.
This is a good place to store resources during a request. For example, a
:meth:`~.Flask.before_request` function could load a user object from a
session id, then set ``g.user`` to be used in the view function.
This is only available when an :doc:`app context </appcontext>` is active.
This is a proxy. See :ref:`context-visibility` for more information.
.. versionchanged:: 0.10
Bound to the application context instead of the request context.
.. autoclass:: flask.ctx._AppCtxGlobals
:members:
Useful Functions and Classes
----------------------------
.. data:: current_app
A proxy to the :class:`.Flask` application handling the current request or
other activity.
This is useful to access the application without needing to import it, or if
it can't be imported, such as when using the application factory pattern or
in blueprints and extensions.
This is only available when an :doc:`app context </appcontext>` is active.
This is a proxy. See :ref:`context-visibility` for more information.
.. autofunction:: has_request_context
.. autofunction:: copy_current_request_context
.. autofunction:: has_app_context
.. autofunction:: url_for
.. autofunction:: abort
.. autofunction:: redirect
.. autofunction:: make_response
.. autofunction:: after_this_request
.. autofunction:: send_file
.. autofunction:: send_from_directory
Message Flashing
----------------
.. autofunction:: flash
.. autofunction:: get_flashed_messages
JSON Support
------------
.. module:: flask.json
Flask uses Python's built-in :mod:`json` module for handling JSON by
default. The JSON implementation can be changed by assigning a different
provider to :attr:`flask.Flask.json_provider_class` or
:attr:`flask.Flask.json`. The functions provided by ``flask.json`` will
use methods on ``app.json`` if an app context is active.
Jinja's ``|tojson`` filter is configured to use the app's JSON provider.
The filter marks the output with ``|safe``. Use it to render data inside
HTML ``<script>`` tags.
.. sourcecode:: html+jinja
<script>
const names = {{ names|tojson }};
renderChart(names, {{ axis_data|tojson }});
</script>
.. autofunction:: jsonify
.. autofunction:: dumps
.. autofunction:: dump
.. autofunction:: loads
.. autofunction:: load
.. autoclass:: flask.json.provider.JSONProvider
:members:
:member-order: bysource
.. autoclass:: flask.json.provider.DefaultJSONProvider
:members:
:member-order: bysource
.. automodule:: flask.json.tag
Template Rendering
------------------
.. currentmodule:: flask
.. autofunction:: render_template
.. autofunction:: render_template_string
.. autofunction:: stream_template
.. autofunction:: stream_template_string
.. autofunction:: get_template_attribute
Configuration
-------------
.. autoclass:: Config
:members:
Stream Helpers
--------------
.. autofunction:: stream_with_context
Useful Internals
----------------
.. autoclass:: flask.ctx.AppContext
:members:
.. data:: flask.globals.app_ctx
A proxy to the active :class:`.AppContext`.
This is an internal object that is essential to how Flask handles requests.
Accessing this should not be needed in most cases. Most likely you want
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session` instead.
This is only available when a :doc:`request context </appcontext>` is
active.
This is a proxy. See :ref:`context-visibility` for more information.
.. class:: flask.ctx.RequestContext
.. deprecated:: 3.2
Merged with :class:`AppContext`. This alias will be removed in Flask 4.0.
.. data:: flask.globals.request_ctx
.. deprecated:: 3.2
Merged with :data:`.app_ctx`. This alias will be removed in Flask 4.0.
.. autoclass:: flask.blueprints.BlueprintSetupState
:members:
.. _core-signals-list:
Signals
-------
Signals are provided by the `Blinker`_ library. See :doc:`signals` for an introduction.
.. _blinker: https://blinker.readthedocs.io/
.. data:: template_rendered
This signal is sent when a template was successfully rendered. The
signal is invoked with the instance of the template as `template`
and the context as dictionary (named `context`).
Example subscriber::
def log_template_renders(sender, template, context, **extra):
sender.logger.debug('Rendering template "%s" with context %s',
template.name or 'string template',
context)
from flask import template_rendered
template_rendered.connect(log_template_renders, app)
.. data:: flask.before_render_template
:noindex:
This signal is sent before template rendering process. The
signal is invoked with the instance of the template as `template`
and the context as dictionary (named `context`).
Example subscriber::
def log_template_renders(sender, template, context, **extra):
sender.logger.debug('Rendering template "%s" with context %s',
template.name or 'string template',
context)
from flask import before_render_template
before_render_template.connect(log_template_renders, app)
.. data:: request_started
This signal is sent when the request context is set up, before
any request processing happens. Because the request context is already
bound, the subscriber can access the request with the standard global
proxies such as :class:`~flask.request`.
Example subscriber::
def log_request(sender, **extra):
sender.logger.debug('Request context is set up')
from flask import request_started
request_started.connect(log_request, app)
.. data:: request_finished
This signal is sent right before the response is sent to the client.
It is passed the response to be sent named `response`.
Example subscriber::
def log_response(sender, response, **extra):
sender.logger.debug('Request context is about to close down. '
'Response: %s', response)
from flask import request_finished
request_finished.connect(log_response, app)
.. data:: got_request_exception
This signal is sent when an unhandled exception happens during
request processing, including when debugging. The exception is
passed to the subscriber as ``exception``.
This signal is not sent for
:exc:`~werkzeug.exceptions.HTTPException`, or other exceptions that
have error handlers registered, unless the exception was raised from
an error handler.
This example shows how to do some extra logging if a theoretical
``SecurityException`` was raised:
.. code-block:: python
from flask import got_request_exception
def log_security_exception(sender, exception, **extra):
if not isinstance(exception, SecurityException):
return
security_logger.exception(
f"SecurityException at {request.url!r}",
exc_info=exception,
)
got_request_exception.connect(log_security_exception, app)
.. data:: request_tearing_down
This signal is sent when the request is tearing down. This is always
called, even if an exception is caused. Currently functions listening
to this signal are called after the regular teardown handlers, but this
is not something you can rely on.
Example subscriber::
def close_db_connection(sender, **extra):
session.close()
from flask import request_tearing_down
request_tearing_down.connect(close_db_connection, app)
As of Flask 0.9, this will also be passed an `exc` keyword argument
that has a reference to the exception that caused the teardown if
there was one.
.. data:: appcontext_tearing_down
This signal is sent when the app context is tearing down. This is always
called, even if an exception is caused. Currently functions listening
to this signal are called after the regular teardown handlers, but this
is not something you can rely on.
Example subscriber::
def close_db_connection(sender, **extra):
session.close()
from flask import appcontext_tearing_down
appcontext_tearing_down.connect(close_db_connection, app)
This will also be passed an `exc` keyword argument that has a reference
to the exception that caused the teardown if there was one.
.. data:: appcontext_pushed
This signal is sent when an application context is pushed. The sender
is the application. This is usually useful for unittests in order to
temporarily hook in information. For instance it can be used to
set a resource early onto the `g` object.
Example usage::
from contextlib import contextmanager
from flask import appcontext_pushed
@contextmanager
def user_set(app, user):
def handler(sender, **kwargs):
g.user = user
with appcontext_pushed.connected_to(handler, app):
yield
And in the testcode::
def test_user_me(self):
with user_set(app, 'john'):
c = app.test_client()
resp = c.get('/users/me')
assert resp.data == 'username=john'
.. versionadded:: 0.10
.. data:: appcontext_popped
This signal is sent when an application context is popped. The sender
is the application. This usually falls in line with the
:data:`appcontext_tearing_down` signal.
.. versionadded:: 0.10
.. data:: message_flashed
This signal is sent when the application is flashing a message. The
messages is sent as `message` keyword argument and the category as
`category`.
Example subscriber::
recorded = []
def record(sender, message, category, **extra):
recorded.append((message, category))
from flask import message_flashed
message_flashed.connect(record, app)
.. versionadded:: 0.10
Class-Based Views
-----------------
.. versionadded:: 0.7
.. currentmodule:: None
.. autoclass:: flask.views.View
:members:
.. autoclass:: flask.views.MethodView
:members:
.. _url-route-registrations:
URL Route Registrations
-----------------------
Generally there are three ways to define rules for the routing system:
1. You can use the :meth:`flask.Flask.route` decorator.
2. You can use the :meth:`flask.Flask.add_url_rule` function.
3. You can directly access the underlying Werkzeug routing system
which is exposed as :attr:`flask.Flask.url_map`.
Variable parts in the route can be specified with angular brackets
(``/user/<username>``). By default a variable part in the URL accepts any
string without a slash however a different converter can be specified as
well by using ``<converter:name>``.
Variable parts are passed to the view function as keyword arguments.
The following converters are available:
=========== ===============================================
`string` accepts any text without a slash (the default)
`int` accepts integers
`float` like `int` but for floating point values
`path` like the default but also accepts slashes
`any` matches one of the items provided
`uuid` accepts UUID strings
=========== ===============================================
Custom converters can be defined using :attr:`flask.Flask.url_map`.
Here are some examples::
@app.route('/')
def index():
pass
@app.route('/<username>')
def show_user(username):
pass
@app.route('/post/<int:post_id>')
def show_post(post_id):
pass
An important detail to keep in mind is how Flask deals with trailing
slashes. The idea is to keep each URL unique so the following rules
apply:
1. If a rule ends with a slash and is requested without a slash by the
user, the user is automatically redirected to the same page with a
trailing slash attached.
2. If a rule does not end with a trailing slash and the user requests the
page with a trailing slash, a 404 not found is raised.
This is consistent with how web servers deal with static files. This
also makes it possible to use relative link targets safely.
You can also define multiple rules for the same function. They have to be
unique however. Defaults can also be specified. Here for example is a
definition for a URL that accepts an optional page::
@app.route('/users/', defaults={'page': 1})
@app.route('/users/page/<int:page>')
def show_users(page):
pass
This specifies that ``/users/`` will be the URL for page one and
``/users/page/N`` will be the URL for page ``N``.
If a URL contains a default value, it will be redirected to its simpler
form with a 301 redirect. In the above example, ``/users/page/1`` will
be redirected to ``/users/``. If your route handles ``GET`` and ``POST``
requests, make sure the default route only handles ``GET``, as redirects
can't preserve form data. ::
@app.route('/region/', defaults={'id': 1})
@app.route('/region/<int:id>', methods=['GET', 'POST'])
def region(id):
pass
Here are the parameters that :meth:`~flask.Flask.route` and
:meth:`~flask.Flask.add_url_rule` accept. The only difference is that
with the route parameter the view function is defined with the decorator
instead of the `view_func` parameter.
=============== ==========================================================
`rule` the URL rule as string
`endpoint` the endpoint for the registered URL rule. Flask itself
assumes that the name of the view function is the name
of the endpoint if not explicitly stated.
`view_func` the function to call when serving a request to the
provided endpoint. If this is not provided one can
specify the function later by storing it in the
:attr:`~flask.Flask.view_functions` dictionary with the
endpoint as key.
`defaults` A dictionary with defaults for this rule. See the
example above for how defaults work.
`subdomain` specifies the rule for the subdomain in case subdomain
matching is in use. If not specified the default
subdomain is assumed.
`**options` the options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object. A change to
Werkzeug is handling of method options. methods is a list
of methods this rule should be limited to (``GET``, ``POST``
etc.). By default a rule just listens for ``GET`` (and
implicitly ``HEAD``). Starting with Flask 0.6, ``OPTIONS`` is
implicitly added and handled by the standard request
handling. They have to be specified as keyword arguments.
=============== ==========================================================
View Function Options
---------------------
For internal usage the view functions can have some attributes attached to
customize behavior the view function would normally not have control over.
The following attributes can be provided optionally to either override
some defaults to :meth:`~flask.Flask.add_url_rule` or general behavior:
- `__name__`: The name of a function is by default used as endpoint. If
endpoint is provided explicitly this value is used. Additionally this
will be prefixed with the name of the blueprint by default which
cannot be customized from the function itself.
- `methods`: If methods are not provided when the URL rule is added,
Flask will look on the view function object itself if a `methods`
attribute exists. If it does, it will pull the information for the
methods from there.
- `provide_automatic_options`: if this attribute is set Flask will
either force enable or disable the automatic implementation of the
HTTP ``OPTIONS`` response. This can be useful when working with
decorators that want to customize the ``OPTIONS`` response on a per-view
basis.
- `required_methods`: if this attribute is set, Flask will always add
these methods when registering a URL rule even if the methods were
explicitly overridden in the ``route()`` call.
Full example::
def index():
if request.method == 'OPTIONS':
# custom options handling here
...
return 'Hello World!'
index.provide_automatic_options = False
index.methods = ['GET', 'OPTIONS']
app.add_url_rule('/', index)
.. versionadded:: 0.8
The `provide_automatic_options` functionality was added.
Command Line Interface
----------------------
.. currentmodule:: flask.cli
.. autoclass:: FlaskGroup
:members:
.. autoclass:: AppGroup
:members:
.. autoclass:: ScriptInfo
:members:
.. autofunction:: load_dotenv
.. autofunction:: with_appcontext
.. autofunction:: pass_script_info
Marks a function so that an instance of :class:`ScriptInfo` is passed
as first argument to the click callback.
.. autodata:: run_command
.. autodata:: shell_command

@ -0,0 +1,186 @@
The App and Request Context
===========================
The context keeps track of data and objects during a request, CLI command, or
other activity. Rather than passing this data around to every function, the
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session` proxies
are accessed instead.
When handling a request, the context is referred to as the "request context"
because it contains request data in addition to application data. Otherwise,
such as during a CLI command, it is referred to as the "app context". During an
app context, :data:`.current_app` and :data:`.g` are available, while during a
request context :data:`.request` and :data:`.session` are also available.
Purpose of the Context
----------------------
The context and proxies help solve two development issues: circular imports, and
passing around global data during a request.
The :class:`.Flask` application object has attributes, such as
:attr:`~.Flask.config`, that are useful to access within views and other
functions. However, importing the ``app`` instance within the modules in your
project is prone to circular import issues. When using the
:doc:`app factory pattern </patterns/appfactories>` or writing reusable
:doc:`blueprints </blueprints>` or :doc:`extensions </extensions>` there won't
be an ``app`` instance to import at all.
When the application handles a request, it creates a :class:`.Request` object.
Because a *worker* handles only one request at a time, the request data can be
considered global to that worker during that request. Passing it as an argument
through every function during the request becomes verbose and redundant.
Flask solves these issues with the *active context* pattern. Rather than
importing an ``app`` directly, or having to pass it and the request through to
every single function, you import and access the proxies, which point to the
currently active application and request data. This is sometimes referred to
as "context local" data.
Context During Setup
--------------------
If you try to access :data:`.current_app`, :data:`.g`, or anything that uses it,
outside an app context, you'll get this error message:
.. code-block:: pytb
RuntimeError: Working outside of application context.
Attempted to use functionality that expected a current application to be
set. To solve this, set up an app context using 'with app.app_context()'.
See the documentation on app context for more information.
If you see that error while configuring your application, such as when
initializing an extension, you can push a context manually since you have direct
access to the ``app``. Use :meth:`.Flask.app_context` in a ``with`` block.
.. code-block:: python
def create_app():
app = Flask(__name__)
with app.app_context():
init_db()
return app
If you see that error somewhere else in your code not related to setting up the
application, it most likely indicates that you should move that code into a view
function or CLI command.
Context During Testing
----------------------
See :doc:`/testing` for detailed information about managing the context during
tests.
If you try to access :data:`.request`, :data:`.session`, or anything that uses
it, outside a request context, you'll get this error message:
.. code-block:: pytb
RuntimeError: Working outside of request context.
Attempted to use functionality that expected an active HTTP request. See the
documentation on request context for more information.
This will probably only happen during tests. If you see that error somewhere
else in your code not related to testing, it most likely indicates that you
should move that code into a view function.
The primary way to solve this is to use :meth:`.Flask.test_client` to simulate
a full request.
If you only want to unit test one function, rather than a full request, use
:meth:`.Flask.test_request_context` in a ``with`` block.
.. code-block:: python
def generate_report(year):
format = request.args.get("format")
...
with app.test_request_context(
"/make_report/2017", query_string={"format": "short"}
):
generate_report()
.. _context-visibility:
Visibility of the Context
-------------------------
The context will have the same lifetime as an activity, such as a request, CLI
command, or ``with`` block. Various callbacks and signals registered with the
app will be run during the context.
When a Flask application handles a request, it pushes a requet context
to set the active application and request data. When it handles a CLI command,
it pushes an app context to set the active application. When the activity ends,
it pops that context. Proxy objects like :data:`.request`, :data:`.session`,
:data:`.g`, and :data:`.current_app`, are accessible while the context is pushed
and active, and are not accessible after the context is popped.
The context is unique to each thread (or other worker type). The proxies cannot
be passed to another worker, which has a different context space and will not
know about the active context in the parent's space.
Besides being scoped to each worker, the proxy object has a separate type and
identity than the proxied real object. In some cases you'll need access to the
real object, rather than the proxy. Use the
:meth:`~.LocalProxy._get_current_object` method in those cases.
.. code-block:: python
app = current_app._get_current_object()
my_signal.send(app)
Lifecycle of the Context
------------------------
Flask dispatches a request in multiple stages which can affect the request,
response, and how errors are handled. See :doc:`/lifecycle` for a list of all
the steps, callbacks, and signals during each request. The following are the
steps directly related to the context.
- The app context is pushed, the proxies are available.
- The :data:`.appcontext_pushed` signal is sent.
- The request is dispatched.
- Any :meth:`.Flask.teardown_request` decorated functions are called.
- The :data:`.request_tearing_down` signal is sent.
- Any :meth:`.Flask.teardown_appcontext` decorated functions are called.
- The :data:`.appcontext_tearing_down` signal is sent.
- The app context is popped, the proxies are no longer available.
- The :data:`.appcontext_popped` signal is sent.
The teardown callbacks are called by the context when it is popped. They are
called even if there is an unhandled exception during dispatch. They may be
called multiple times in some test scenarios. This means there is no guarantee
that any other parts of the request dispatch have run. Be sure to write these
functions in a way that does not depend on other callbacks and will not fail.
How the Context Works
---------------------
Context locals are implemented using Python's :mod:`contextvars` and Werkzeug's
:class:`~werkzeug.local.LocalProxy`. Python's contextvars are a low level
structure to manage data local to a thread or coroutine. ``LocalProxy`` wraps
the contextvar so that access to any attributes and methods is forwarded to the
object stored in the contextvar.
The context is tracked like a stack, with the active context at the top of the
stack. Flask manages pushing and popping contexts during requests, CLI commands,
testing, ``with`` blocks, etc. The proxies access attributes on the active
context.
Because it is a stack, other contexts may be pushed to change the proxies during
an already active context. This is not a common pattern, but can be used in
advanced use cases. For example, a Flask application can be used as WSGI
middleware, calling another wrapped Flask app from a view.

@ -0,0 +1,125 @@
.. _async_await:
Using ``async`` and ``await``
=============================
.. versionadded:: 2.0
Routes, error handlers, before request, after request, and teardown
functions can all be coroutine functions if Flask is installed with the
``async`` extra (``pip install flask[async]``). This allows views to be
defined with ``async def`` and use ``await``.
.. code-block:: python
@app.route("/get-data")
async def get_data():
data = await async_db_query(...)
return jsonify(data)
Pluggable class-based views also support handlers that are implemented as
coroutines. This applies to the :meth:`~flask.views.View.dispatch_request`
method in views that inherit from the :class:`flask.views.View` class, as
well as all the HTTP method handlers in views that inherit from the
:class:`flask.views.MethodView` class.
.. admonition:: Using ``async`` with greenlet
When using gevent or eventlet to serve an application or patch the
runtime, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
Performance
-----------
Async functions require an event loop to run. Flask, as a WSGI
application, uses one worker to handle one request/response cycle.
When a request comes in to an async view, Flask will start an event loop
in a thread, run the view function there, then return the result.
Each request still ties up one worker, even for async views. The upside
is that you can run async code within a view, for example to make
multiple concurrent database queries, HTTP requests to an external API,
etc. However, the number of requests your application can handle at one
time will remain the same.
**Async is not inherently faster than sync code.** Async is beneficial
when performing concurrent IO-bound tasks, but will probably not improve
CPU-bound tasks. Traditional Flask views will still be appropriate for
most use cases, but Flask's async support enables writing and using
code that wasn't possible natively before.
Background tasks
----------------
Async functions will run in an event loop until they complete, at
which stage the event loop will stop. This means any additional
spawned tasks that haven't completed when the async function completes
will be cancelled. Therefore you cannot spawn background tasks, for
example via ``asyncio.create_task``.
If you wish to use background tasks it is best to use a task queue to
trigger background work, rather than spawn tasks in a view
function. With that in mind you can spawn asyncio tasks by serving
Flask with an ASGI server and utilising the asgiref WsgiToAsgi adapter
as described in :doc:`deploying/asgi`. This works as the adapter creates
an event loop that runs continually.
When to use Quart instead
-------------------------
Flask's async support is less performant than async-first frameworks due
to the way it is implemented. If you have a mainly async codebase it
would make sense to consider `Quart`_. Quart is a reimplementation of
Flask based on the `ASGI`_ standard instead of WSGI. This allows it to
handle many concurrent requests, long running requests, and websockets
without requiring multiple worker processes or threads.
It has also already been possible to run Flask with Gevent or Eventlet
to get many of the benefits of async request handling. These libraries
patch low-level Python functions to accomplish this, whereas ``async``/
``await`` and ASGI use standard, modern Python capabilities. Deciding
whether you should use Flask, Quart, or something else is ultimately up
to understanding the specific needs of your project.
.. _Quart: https://github.com/pallets/quart
.. _ASGI: https://asgi.readthedocs.io/en/latest/
Extensions
----------
Flask extensions predating Flask's async support do not expect async views.
If they provide decorators to add functionality to views, those will probably
not work with async views because they will not await the function or be
awaitable. Other functions they provide will not be awaitable either and
will probably be blocking if called within an async view.
Extension authors can support async functions by utilising the
:meth:`flask.Flask.ensure_sync` method. For example, if the extension
provides a view function decorator add ``ensure_sync`` before calling
the decorated function,
.. code-block:: python
def extension(func):
@wraps(func)
def wrapper(*args, **kwargs):
... # Extension logic
return current_app.ensure_sync(func)(*args, **kwargs)
return wrapper
Check the changelog of the extension you want to use to see if they've
implemented async support, or make a feature request or PR to them.
Other event loops
-----------------
At the moment Flask only supports :mod:`asyncio`. It's possible to
override :meth:`flask.Flask.ensure_sync` to change how async functions
are wrapped to use a different library.

@ -0,0 +1,315 @@
Modular Applications with Blueprints
====================================
.. currentmodule:: flask
.. versionadded:: 0.7
Flask uses a concept of *blueprints* for making application components and
supporting common patterns within an application or across applications.
Blueprints can greatly simplify how large applications work and provide a
central means for Flask extensions to register operations on applications.
A :class:`Blueprint` object works similarly to a :class:`Flask`
application object, but it is not actually an application. Rather it is a
*blueprint* of how to construct or extend an application.
Why Blueprints?
---------------
Blueprints in Flask are intended for these cases:
* Factor an application into a set of blueprints. This is ideal for
larger applications; a project could instantiate an application object,
initialize several extensions, and register a collection of blueprints.
* Register a blueprint on an application at a URL prefix and/or subdomain.
Parameters in the URL prefix/subdomain become common view arguments
(with defaults) across all view functions in the blueprint.
* Register a blueprint multiple times on an application with different URL
rules.
* Provide template filters, static files, templates, and other utilities
through blueprints. A blueprint does not have to implement applications
or view functions.
* Register a blueprint on an application for any of these cases when
initializing a Flask extension.
A blueprint in Flask is not a pluggable app because it is not actually an
application -- it's a set of operations which can be registered on an
application, even multiple times. Why not have multiple application
objects? You can do that (see :doc:`/patterns/appdispatch`), but your
applications will have separate configs and will be managed at the WSGI
layer.
Blueprints instead provide separation at the Flask level, share
application config, and can change an application object as necessary with
being registered. The downside is that you cannot unregister a blueprint
once an application was created without having to destroy the whole
application object.
The Concept of Blueprints
-------------------------
The basic concept of blueprints is that they record operations to execute
when registered on an application. Flask associates view functions with
blueprints when dispatching requests and generating URLs from one endpoint
to another.
My First Blueprint
------------------
This is what a very basic blueprint looks like. In this case we want to
implement a blueprint that does simple rendering of static templates::
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
simple_page = Blueprint('simple_page', __name__,
template_folder='templates')
@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
try:
return render_template(f'pages/{page}.html')
except TemplateNotFound:
abort(404)
When you bind a function with the help of the ``@simple_page.route``
decorator, the blueprint will record the intention of registering the
function ``show`` on the application when it's later registered.
Additionally it will prefix the endpoint of the function with the
name of the blueprint which was given to the :class:`Blueprint`
constructor (in this case also ``simple_page``). The blueprint's name
does not modify the URL, only the endpoint.
Registering Blueprints
----------------------
So how do you register that blueprint? Like this::
from flask import Flask
from yourapplication.simple_page import simple_page
app = Flask(__name__)
app.register_blueprint(simple_page)
If you check the rules registered on the application, you will find
these::
>>> app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
<Rule '/' (HEAD, OPTIONS, GET) -> simple_page.show>])
The first one is obviously from the application itself for the static
files. The other two are for the `show` function of the ``simple_page``
blueprint. As you can see, they are also prefixed with the name of the
blueprint and separated by a dot (``.``).
Blueprints however can also be mounted at different locations::
app.register_blueprint(simple_page, url_prefix='/pages')
And sure enough, these are the generated rules::
>>> app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/pages/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
<Rule '/pages/' (HEAD, OPTIONS, GET) -> simple_page.show>])
On top of that you can register blueprints multiple times though not every
blueprint might respond properly to that. In fact it depends on how the
blueprint is implemented if it can be mounted more than once.
Nesting Blueprints
------------------
It is possible to register a blueprint on another blueprint.
.. code-block:: python
parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)
The child blueprint will gain the parent's name as a prefix to its
name, and child URLs will be prefixed with the parent's URL prefix.
.. code-block:: python
url_for('parent.child.create')
/parent/child/create
In addition a child blueprint's will gain their parent's subdomain,
with their subdomain as prefix if present i.e.
.. code-block:: python
parent = Blueprint('parent', __name__, subdomain='parent')
child = Blueprint('child', __name__, subdomain='child')
parent.register_blueprint(child)
app.register_blueprint(parent)
url_for('parent.child.create', _external=True)
"child.parent.domain.tld"
Blueprint-specific before request functions, etc. registered with the
parent will trigger for the child. If a child does not have an error
handler that can handle a given exception, the parent's will be tried.
Blueprint Resources
-------------------
Blueprints can provide resources as well. Sometimes you might want to
introduce a blueprint only for the resources it provides.
Blueprint Resource Folder
`````````````````````````
Like for regular applications, blueprints are considered to be contained
in a folder. While multiple blueprints can originate from the same folder,
it does not have to be the case and it's usually not recommended.
The folder is inferred from the second argument to :class:`Blueprint` which
is usually `__name__`. This argument specifies what logical Python
module or package corresponds to the blueprint. If it points to an actual
Python package that package (which is a folder on the filesystem) is the
resource folder. If it's a module, the package the module is contained in
will be the resource folder. You can access the
:attr:`Blueprint.root_path` property to see what the resource folder is::
>>> simple_page.root_path
'/Users/username/TestProject/yourapplication'
To quickly open sources from this folder you can use the
:meth:`~Blueprint.open_resource` function::
with simple_page.open_resource('static/style.css') as f:
code = f.read()
Static Files
````````````
A blueprint can expose a folder with static files by providing the path
to the folder on the filesystem with the ``static_folder`` argument.
It is either an absolute path or relative to the blueprint's location::
admin = Blueprint('admin', __name__, static_folder='static')
By default the rightmost part of the path is where it is exposed on the
web. This can be changed with the ``static_url_path`` argument. Because the
folder is called ``static`` here it will be available at the
``url_prefix`` of the blueprint + ``/static``. If the blueprint
has the prefix ``/admin``, the static URL will be ``/admin/static``.
The endpoint is named ``blueprint_name.static``. You can generate URLs
to it with :func:`url_for` like you would with the static folder of the
application::
url_for('admin.static', filename='style.css')
However, if the blueprint does not have a ``url_prefix``, it is not
possible to access the blueprint's static folder. This is because the
URL would be ``/static`` in this case, and the application's ``/static``
route takes precedence. Unlike template folders, blueprint static
folders are not searched if the file does not exist in the application
static folder.
Templates
`````````
If you want the blueprint to expose templates you can do that by providing
the `template_folder` parameter to the :class:`Blueprint` constructor::
admin = Blueprint('admin', __name__, template_folder='templates')
For static files, the path can be absolute or relative to the blueprint
resource folder.
The template folder is added to the search path of templates but with a lower
priority than the actual application's template folder. That way you can
easily override templates that a blueprint provides in the actual application.
This also means that if you don't want a blueprint template to be accidentally
overridden, make sure that no other blueprint or actual application template
has the same relative path. When multiple blueprints provide the same relative
template path the first blueprint registered takes precedence over the others.
So if you have a blueprint in the folder ``yourapplication/admin`` and you
want to render the template ``'admin/index.html'`` and you have provided
``templates`` as a `template_folder` you will have to create a file like
this: :file:`yourapplication/admin/templates/admin/index.html`. The reason
for the extra ``admin`` folder is to avoid getting our template overridden
by a template named ``index.html`` in the actual application template
folder.
To further reiterate this: if you have a blueprint named ``admin`` and you
want to render a template called :file:`index.html` which is specific to this
blueprint, the best idea is to lay out your templates like this::
yourpackage/
blueprints/
admin/
templates/
admin/
index.html
__init__.py
And then when you want to render the template, use :file:`admin/index.html` as
the name to look up the template by. If you encounter problems loading
the correct templates enable the ``EXPLAIN_TEMPLATE_LOADING`` config
variable which will instruct Flask to print out the steps it goes through
to locate templates on every ``render_template`` call.
Building URLs
-------------
If you want to link from one page to another you can use the
:func:`url_for` function just like you normally would do just that you
prefix the URL endpoint with the name of the blueprint and a dot (``.``)::
url_for('admin.index')
Additionally if you are in a view function of a blueprint or a rendered
template and you want to link to another endpoint of the same blueprint,
you can use relative redirects by prefixing the endpoint with a dot only::
url_for('.index')
This will link to ``admin.index`` for instance in case the current request
was dispatched to any other admin blueprint endpoint.
Blueprint Error Handlers
------------------------
Blueprints support the ``errorhandler`` decorator just like the :class:`Flask`
application object, so it is easy to make Blueprint-specific custom error
pages.
Here is an example for a "404 Page Not Found" exception::
@simple_page.errorhandler(404)
def page_not_found(e):
return render_template('pages/404.html')
Most errorhandlers will simply work as expected; however, there is a caveat
concerning handlers for 404 and 405 exceptions. These errorhandlers are only
invoked from an appropriate ``raise`` statement or a call to ``abort`` in another
of the blueprint's view functions; they are not invoked by, e.g., an invalid URL
access. This is because the blueprint does not "own" a certain URL space, so
the application instance has no way of knowing which blueprint error handler it
should run if given an invalid URL. If you would like to execute different
handling strategies for these errors based on URL prefixes, they may be defined
at the application level using the ``request`` proxy object::
@app.errorhandler(404)
@app.errorhandler(405)
def _handle_api_error(ex):
if request.path.startswith('/api/'):
return jsonify(error=str(ex)), ex.code
else:
return ex
See :doc:`/errorhandling`.

@ -0,0 +1,4 @@
Changes
=======
.. include:: ../CHANGES.rst

@ -0,0 +1,556 @@
.. currentmodule:: flask
Command Line Interface
======================
Installing Flask installs the ``flask`` script, a `Click`_ command line
interface, in your virtualenv. Executed from the terminal, this script gives
access to built-in, extension, and application-defined commands. The ``--help``
option will give more information about any commands and options.
.. _Click: https://click.palletsprojects.com/
Application Discovery
---------------------
The ``flask`` command is installed by Flask, not your application; it must be
told where to find your application in order to use it. The ``--app``
option is used to specify how to load the application.
While ``--app`` supports a variety of options for specifying your
application, most use cases should be simple. Here are the typical values:
(nothing)
The name "app" or "wsgi" is imported (as a ".py" file, or package),
automatically detecting an app (``app`` or ``application``) or
factory (``create_app`` or ``make_app``).
``--app hello``
The given name is imported, automatically detecting an app (``app``
or ``application``) or factory (``create_app`` or ``make_app``).
----
``--app`` has three parts: an optional path that sets the current working
directory, a Python file or dotted import path, and an optional variable
name of the instance or factory. If the name is a factory, it can optionally
be followed by arguments in parentheses. The following values demonstrate these
parts:
``--app src/hello``
Sets the current working directory to ``src`` then imports ``hello``.
``--app hello.web``
Imports the path ``hello.web``.
``--app hello:app2``
Uses the ``app2`` Flask instance in ``hello``.
``--app 'hello:create_app("dev")'``
The ``create_app`` factory in ``hello`` is called with the string ``'dev'``
as the argument.
If ``--app`` is not set, the command will try to import "app" or
"wsgi" (as a ".py" file, or package) and try to detect an application
instance or factory.
Within the given import, the command looks for an application instance named
``app`` or ``application``, then any application instance. If no instance is
found, the command looks for a factory function named ``create_app`` or
``make_app`` that returns an instance.
If parentheses follow the factory name, their contents are parsed as
Python literals and passed as arguments and keyword arguments to the
function. This means that strings must still be in quotes.
Run the Development Server
--------------------------
The :func:`run <cli.run_command>` command will start the development server. It
replaces the :meth:`Flask.run` method in most cases. ::
$ flask --app hello run
* Serving Flask app "hello"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
.. warning:: Do not use this command to run your application in production.
Only use the development server during development. The development server
is provided for convenience, but is not designed to be particularly secure,
stable, or efficient. See :doc:`/deploying/index` for how to run in production.
If another program is already using port 5000, you'll see
``OSError: [Errno 98]`` or ``OSError: [WinError 10013]`` when the
server tries to start. See :ref:`address-already-in-use` for how to
handle that.
Debug Mode
~~~~~~~~~~
In debug mode, the ``flask run`` command will enable the interactive debugger and the
reloader by default, and make errors easier to see and debug. To enable debug mode, use
the ``--debug`` option.
.. code-block:: console
$ flask --app hello run --debug
* Serving Flask app "hello"
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
The ``--debug`` option can also be passed to the top level ``flask`` command to enable
debug mode for any command. The following two ``run`` calls are equivalent.
.. code-block:: console
$ flask --app hello --debug run
$ flask --app hello run --debug
Watch and Ignore Files with the Reloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using debug mode, the reloader will trigger whenever your Python code or imported
modules change. The reloader can watch additional files with the ``--extra-files``
option. Multiple paths are separated with ``:``, or ``;`` on Windows.
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
The reloader can also ignore files using :mod:`fnmatch` patterns with the
``--exclude-patterns`` option. Multiple patterns are separated with ``:``, or ``;`` on
Windows.
Open a Shell
------------
To explore the data in your application, you can start an interactive Python
shell with the :func:`shell <cli.shell_command>` command. An application
context will be active, and the app instance will be imported. ::
$ flask shell
Python 3.10.0 (default, Oct 27 2021, 06:59:51) [GCC 11.1.0] on linux
App: example [production]
Instance: /home/david/Projects/pallets/flask/instance
>>>
Use :meth:`~Flask.shell_context_processor` to add other automatic imports.
.. _dotenv:
Environment Variables From dotenv
---------------------------------
The ``flask`` command supports setting any option for any command with
environment variables. The variables are named like ``FLASK_OPTION`` or
``FLASK_COMMAND_OPTION``, for example ``FLASK_APP`` or
``FLASK_RUN_PORT``.
Rather than passing options every time you run a command, or environment
variables every time you open a new terminal, you can use Flask's dotenv
support to set environment variables automatically.
If `python-dotenv`_ is installed, running the ``flask`` command will set
environment variables defined in the files ``.env`` and ``.flaskenv``.
You can also specify an extra file to load with the ``--env-file``
option. Dotenv files can be used to avoid having to set ``--app`` or
``FLASK_APP`` manually, and to set configuration using environment
variables similar to how some deployment services work.
Variables set on the command line are used over those set in :file:`.env`,
which are used over those set in :file:`.flaskenv`. :file:`.flaskenv` should be
used for public variables, such as ``FLASK_APP``, while :file:`.env` should not
be committed to your repository so that it can set private variables.
Directories are scanned upwards from the directory you call ``flask``
from to locate the files.
The files are only loaded by the ``flask`` command or calling
:meth:`~Flask.run`. If you would like to load these files when running in
production, you should call :func:`~cli.load_dotenv` manually.
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
Setting Command Options
~~~~~~~~~~~~~~~~~~~~~~~
Click is configured to load default values for command options from
environment variables. The variables use the pattern
``FLASK_COMMAND_OPTION``. For example, to set the port for the run
command, instead of ``flask run --port 8000``:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_RUN_PORT=8000
$ flask run
* Running on http://127.0.0.1:8000/
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_RUN_PORT 8000
$ flask run
* Running on http://127.0.0.1:8000/
.. group-tab:: CMD
.. code-block:: text
> set FLASK_RUN_PORT=8000
> flask run
* Running on http://127.0.0.1:8000/
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_RUN_PORT = 8000
> flask run
* Running on http://127.0.0.1:8000/
These can be added to the ``.flaskenv`` file just like ``FLASK_APP`` to
control default command options.
Disable dotenv
~~~~~~~~~~~~~~
The ``flask`` command will show a message if it detects dotenv files but
python-dotenv is not installed.
.. code-block:: bash
$ flask run
* Tip: There are .env files present. Do "pip install python-dotenv" to use them.
You can tell Flask not to load dotenv files even when python-dotenv is
installed by setting the ``FLASK_SKIP_DOTENV`` environment variable.
This can be useful if you want to load them manually, or if you're using
a project runner that loads them already. Keep in mind that the
environment variables must be set before the app loads or it won't
configure as expected.
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_SKIP_DOTENV=1
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_SKIP_DOTENV 1
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_SKIP_DOTENV=1
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_SKIP_DOTENV = 1
> flask run
Environment Variables From virtualenv
-------------------------------------
If you do not want to install dotenv support, you can still set environment
variables by adding them to the end of the virtualenv's :file:`activate`
script. Activating the virtualenv will set the variables.
.. tabs::
.. group-tab:: Bash
Unix Bash, :file:`.venv/bin/activate`::
$ export FLASK_APP=hello
.. group-tab:: Fish
Fish, :file:`.venv/bin/activate.fish`::
$ set -x FLASK_APP hello
.. group-tab:: CMD
Windows CMD, :file:`.venv\\Scripts\\activate.bat`::
> set FLASK_APP=hello
.. group-tab:: Powershell
Windows Powershell, :file:`.venv\\Scripts\\activate.ps1`::
> $env:FLASK_APP = "hello"
It is preferred to use dotenv support over this, since :file:`.flaskenv` can be
committed to the repository so that it works automatically wherever the project
is checked out.
Custom Commands
---------------
The ``flask`` command is implemented using `Click`_. See that project's
documentation for full information about writing commands.
This example adds the command ``create-user`` that takes the argument
``name``. ::
import click
from flask import Flask
app = Flask(__name__)
@app.cli.command("create-user")
@click.argument("name")
def create_user(name):
...
::
$ flask create-user admin
This example adds the same command, but as ``user create``, a command in a
group. This is useful if you want to organize multiple related commands. ::
import click
from flask import Flask
from flask.cli import AppGroup
app = Flask(__name__)
user_cli = AppGroup('user')
@user_cli.command('create')
@click.argument('name')
def create_user(name):
...
app.cli.add_command(user_cli)
::
$ flask user create demo
See :ref:`testing-cli` for an overview of how to test your custom
commands.
Registering Commands with Blueprints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your application uses blueprints, you can optionally register CLI
commands directly onto them. When your blueprint is registered onto your
application, the associated commands will be available to the ``flask``
command. By default, those commands will be nested in a group matching
the name of the blueprint.
.. code-block:: python
from flask import Blueprint
bp = Blueprint('students', __name__)
@bp.cli.command('create')
@click.argument('name')
def create(name):
...
app.register_blueprint(bp)
.. code-block:: text
$ flask students create alice
You can alter the group name by specifying the ``cli_group`` parameter
when creating the :class:`Blueprint` object, or later with
:meth:`app.register_blueprint(bp, cli_group='...') <Flask.register_blueprint>`.
The following are equivalent:
.. code-block:: python
bp = Blueprint('students', __name__, cli_group='other')
# or
app.register_blueprint(bp, cli_group='other')
.. code-block:: text
$ flask other create alice
Specifying ``cli_group=None`` will remove the nesting and merge the
commands directly to the application's level:
.. code-block:: python
bp = Blueprint('students', __name__, cli_group=None)
# or
app.register_blueprint(bp, cli_group=None)
.. code-block:: text
$ flask create alice
Application Context
~~~~~~~~~~~~~~~~~~~
Commands added using the Flask app's :attr:`~Flask.cli` or
:class:`~flask.cli.FlaskGroup` :meth:`~cli.AppGroup.command` decorator
will be executed with an application context pushed, so your custom
commands and parameters have access to the app and its configuration. The
:func:`~cli.with_appcontext` decorator can be used to get the same
behavior, but is not needed in most cases.
.. code-block:: python
import click
from flask.cli import with_appcontext
@click.command()
@with_appcontext
def do_work():
...
app.cli.add_command(do_work)
Plugins
-------
Flask will automatically load commands specified in the ``flask.commands``
`entry point`_. This is useful for extensions that want to add commands when
they are installed. Entry points are specified in :file:`pyproject.toml`:
.. code-block:: toml
[project.entry-points."flask.commands"]
my-command = "my_extension.commands:cli"
.. _entry point: https://packaging.python.org/tutorials/packaging-projects/#entry-points
Inside :file:`my_extension/commands.py` you can then export a Click
object::
import click
@click.command()
def cli():
...
Once that package is installed in the same virtualenv as your Flask project,
you can run ``flask my-command`` to invoke the command.
.. _custom-scripts:
Custom Scripts
--------------
When you are using the app factory pattern, it may be more convenient to define
your own Click script. Instead of using ``--app`` and letting Flask load
your application, you can create your own Click object and export it as a
`console script`_ entry point.
Create an instance of :class:`~cli.FlaskGroup` and pass it the factory::
import click
from flask import Flask
from flask.cli import FlaskGroup
def create_app():
app = Flask('wiki')
# other setup
return app
@click.group(cls=FlaskGroup, create_app=create_app)
def cli():
"""Management script for the Wiki application."""
Define the entry point in :file:`pyproject.toml`:
.. code-block:: toml
[project.scripts]
wiki = "wiki:cli"
Install the application in the virtualenv in editable mode and the custom
script is available. Note that you don't need to set ``--app``. ::
$ pip install -e .
$ wiki run
.. admonition:: Errors in Custom Scripts
When using a custom script, if you introduce an error in your
module-level code, the reloader will fail because it can no longer
load the entry point.
The ``flask`` command, being separate from your code, does not have
this issue and is recommended in most cases.
.. _console script: https://packaging.python.org/tutorials/packaging-projects/#console-scripts
PyCharm Integration
-------------------
PyCharm Professional provides a special Flask run configuration to run the development
server. For the Community Edition, and for other commands besides ``run``, you need to
create a custom run configuration. These instructions should be similar for any other
IDE you use.
In PyCharm, with your project open, click on *Run* from the menu bar and go to *Edit
Configurations*. You'll see a screen similar to this:
.. image:: _static/pycharm-run-config.png
:align: center
:class: screenshot
:alt: Screenshot of PyCharm run configuration.
Once you create a configuration for the ``flask run``, you can copy and change it to
call any other command.
Click the *+ (Add New Configuration)* button and select *Python*. Give the configuration
a name such as "flask run".
Click the *Script path* dropdown and change it to *Module name*, then input ``flask``.
The *Parameters* field is set to the CLI command to execute along with any arguments.
This example uses ``--app hello run --debug``, which will run the development server in
debug mode. ``--app hello`` should be the import or file with your Flask app.
If you installed your project as a package in your virtualenv, you may uncheck the
*PYTHONPATH* options. This will more accurately match how you deploy later.
Click *OK* to save and close the configuration. Select the configuration in the main
PyCharm window and click the play button next to it to run the server.
Now that you have a configuration for ``flask run``, you can copy that configuration and
change the *Parameters* argument to run a different CLI command.

@ -0,0 +1,101 @@
import packaging.version
from pallets_sphinx_themes import get_version
from pallets_sphinx_themes import ProjectLink
# Project --------------------------------------------------------------
project = "Flask"
copyright = "2010 Pallets"
author = "Pallets"
release, version = get_version("Flask")
# General --------------------------------------------------------------
default_role = "code"
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinxcontrib.log_cabinet",
"sphinx_tabs.tabs",
"pallets_sphinx_themes",
]
autodoc_member_order = "bysource"
autodoc_typehints = "description"
autodoc_preserve_defaults = True
extlinks = {
"issue": ("https://github.com/pallets/flask/issues/%s", "#%s"),
"pr": ("https://github.com/pallets/flask/pull/%s", "#%s"),
"ghsa": ("https://github.com/pallets/flask/security/advisories/GHSA-%s", "GHSA-%s"),
}
intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
"werkzeug": ("https://werkzeug.palletsprojects.com/", None),
"click": ("https://click.palletsprojects.com/", None),
"jinja": ("https://jinja.palletsprojects.com/", None),
"itsdangerous": ("https://itsdangerous.palletsprojects.com/", None),
"sqlalchemy": ("https://docs.sqlalchemy.org/", None),
"wtforms": ("https://wtforms.readthedocs.io/", None),
"blinker": ("https://blinker.readthedocs.io/", None),
}
# HTML -----------------------------------------------------------------
html_theme = "flask"
html_theme_options = {"index_sidebar_logo": False}
html_context = {
"project_links": [
ProjectLink("Donate", "https://palletsprojects.com/donate"),
ProjectLink("PyPI Releases", "https://pypi.org/project/Flask/"),
ProjectLink("Source Code", "https://github.com/pallets/flask/"),
ProjectLink("Issue Tracker", "https://github.com/pallets/flask/issues/"),
ProjectLink("Chat", "https://discord.gg/pallets"),
]
}
html_sidebars = {
"index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"],
"**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"],
}
singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
html_static_path = ["_static"]
html_favicon = "_static/flask-icon.svg"
html_logo = "_static/flask-logo.svg"
html_title = f"Flask Documentation ({version})"
html_show_sourcelink = False
gettext_uuid = True
gettext_compact = False
# Local Extensions -----------------------------------------------------
def github_link(name, rawtext, text, lineno, inliner, options=None, content=None):
app = inliner.document.settings.env.app
release = app.config.release
base_url = "https://github.com/pallets/flask/tree/"
if text.endswith(">"):
words, text = text[:-1].rsplit("<", 1)
words = words.strip()
else:
words = None
if packaging.version.parse(release).is_devrelease:
url = f"{base_url}main/{text}"
else:
url = f"{base_url}{release}/{text}"
if words is None:
words = url
from docutils.nodes import reference
from docutils.parsers.rst.roles import set_classes
options = options or {}
set_classes(options)
node = reference(rawtext, words, refuri=url, **options)
return [node], []
def setup(app):
app.add_role("gh", github_link)

@ -0,0 +1,839 @@
Configuration Handling
======================
Applications need some kind of configuration. There are different settings
you might want to change depending on the application environment like
toggling the debug mode, setting the secret key, and other such
environment-specific things.
The way Flask is designed usually requires the configuration to be
available when the application starts up. You can hard code the
configuration in the code, which for many small applications is not
actually that bad, but there are better ways.
Independent of how you load your config, there is a config object
available which holds the loaded configuration values:
The :attr:`~flask.Flask.config` attribute of the :class:`~flask.Flask`
object. This is the place where Flask itself puts certain configuration
values and also where extensions can put their configuration values. But
this is also where you can have your own configuration.
Configuration Basics
--------------------
The :attr:`~flask.Flask.config` is actually a subclass of a dictionary and
can be modified just like any dictionary::
app = Flask(__name__)
app.config['TESTING'] = True
Certain configuration values are also forwarded to the
:attr:`~flask.Flask` object so you can read and write them from there::
app.testing = True
To update multiple keys at once you can use the :meth:`dict.update`
method::
app.config.update(
TESTING=True,
SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
)
Debug Mode
----------
The :data:`DEBUG` config value is special because it may behave inconsistently if
changed after the app has begun setting up. In order to set debug mode reliably, use the
``--debug`` option on the ``flask`` or ``flask run`` command. ``flask run`` will use the
interactive debugger and reloader by default in debug mode.
.. code-block:: text
$ flask --app hello run --debug
Using the option is recommended. While it is possible to set :data:`DEBUG` in your
config or code, this is strongly discouraged. It can't be read early by the
``flask run`` command, and some systems or extensions may have already configured
themselves based on a previous value.
Builtin Configuration Values
----------------------------
The following configuration values are used internally by Flask:
.. py:data:: DEBUG
Whether debug mode is enabled. When using ``flask run`` to start the development
server, an interactive debugger will be shown for unhandled exceptions, and the
server will be reloaded when code changes. The :attr:`~flask.Flask.debug` attribute
maps to this config key. This is set with the ``FLASK_DEBUG`` environment variable.
It may not behave as expected if set in code.
**Do not enable debug mode when deploying in production.**
Default: ``False``
.. py:data:: TESTING
Enable testing mode. Exceptions are propagated rather than handled by the
the app's error handlers. Extensions may also change their behavior to
facilitate easier testing. You should enable this in your own tests.
Default: ``False``
.. py:data:: PROPAGATE_EXCEPTIONS
Exceptions are re-raised rather than being handled by the app's error
handlers. If not set, this is implicitly true if ``TESTING`` or ``DEBUG``
is enabled.
Default: ``None``
.. py:data:: TRAP_HTTP_EXCEPTIONS
If there is no handler for an ``HTTPException``-type exception, re-raise it
to be handled by the interactive debugger instead of returning it as a
simple error response.
Default: ``False``
.. py:data:: TRAP_BAD_REQUEST_ERRORS
Trying to access a key that doesn't exist from request dicts like ``args``
and ``form`` will return a 400 Bad Request error page. Enable this to treat
the error as an unhandled exception instead so that you get the interactive
debugger. This is a more specific version of ``TRAP_HTTP_EXCEPTIONS``. If
unset, it is enabled in debug mode.
Default: ``None``
.. py:data:: SECRET_KEY
A secret key that will be used for securely signing the session cookie
and can be used for any other security related needs by extensions or your
application. It should be a long random ``bytes`` or ``str``. For
example, copy the output of this to your config::
$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
**Do not reveal the secret key when posting questions or committing code.**
Default: ``None``
.. py:data:: SECRET_KEY_FALLBACKS
A list of old secret keys that can still be used for unsigning. This allows
a project to implement key rotation without invalidating active sessions or
other recently-signed secrets.
Keys should be removed after an appropriate period of time, as checking each
additional key adds some overhead.
Order should not matter, but the default implementation will test the last
key in the list first, so it might make sense to order oldest to newest.
Flask's built-in secure cookie session supports this. Extensions that use
:data:`SECRET_KEY` may not support this yet.
Default: ``None``
.. versionadded:: 3.1
.. py:data:: SESSION_COOKIE_NAME
The name of the session cookie. Can be changed in case you already have a
cookie with the same name.
Default: ``'session'``
.. py:data:: SESSION_COOKIE_DOMAIN
The value of the ``Domain`` parameter on the session cookie. If not set, browsers
will only send the cookie to the exact domain it was set from. Otherwise, they
will send it to any subdomain of the given value as well.
Not setting this value is more restricted and secure than setting it.
Default: ``None``
.. warning::
If this is changed after the browser created a cookie is created with
one setting, it may result in another being created. Browsers may send
send both in an undefined order. In that case, you may want to change
:data:`SESSION_COOKIE_NAME` as well or otherwise invalidate old sessions.
.. versionchanged:: 2.3
Not set by default, does not fall back to ``SERVER_NAME``.
.. py:data:: SESSION_COOKIE_PATH
The path that the session cookie will be valid for. If not set, the cookie
will be valid underneath ``APPLICATION_ROOT`` or ``/`` if that is not set.
Default: ``None``
.. py:data:: SESSION_COOKIE_HTTPONLY
Browsers will not allow JavaScript access to cookies marked as "HTTP only"
for security.
Default: ``True``
.. py:data:: SESSION_COOKIE_SECURE
Browsers will only send cookies with requests over HTTPS if the cookie is
marked "secure". The application must be served over HTTPS for this to make
sense.
Default: ``False``
.. py:data:: SESSION_COOKIE_PARTITIONED
Browsers will send cookies based on the top-level document's domain, rather
than only the domain of the document setting the cookie. This prevents third
party cookies set in iframes from "leaking" between separate sites.
Browsers are beginning to disallow non-partitioned third party cookies, so
you need to mark your cookies partitioned if you expect them to work in such
embedded situations.
Enabling this implicitly enables :data:`SESSION_COOKIE_SECURE` as well, as
it is only valid when served over HTTPS.
Default: ``False``
.. versionadded:: 3.1
.. py:data:: SESSION_COOKIE_SAMESITE
Restrict how cookies are sent with requests from external sites. Can
be set to ``'Lax'`` (recommended) or ``'Strict'``.
See :ref:`security-cookie`.
Default: ``None``
.. versionadded:: 1.0
.. py:data:: PERMANENT_SESSION_LIFETIME
If ``session.permanent`` is true, the cookie's expiration will be set this
number of seconds in the future. Can either be a
:class:`datetime.timedelta` or an ``int``.
Flask's default cookie implementation validates that the cryptographic
signature is not older than this value.
Default: ``timedelta(days=31)`` (``2678400`` seconds)
.. py:data:: SESSION_REFRESH_EACH_REQUEST
Control whether the cookie is sent with every response when
``session.permanent`` is true. Sending the cookie every time (the default)
can more reliably keep the session from expiring, but uses more bandwidth.
Non-permanent sessions are not affected.
Default: ``True``
.. py:data:: USE_X_SENDFILE
When serving files, set the ``X-Sendfile`` header instead of serving the
data with Flask. Some web servers, such as Apache, recognize this and serve
the data more efficiently. This only makes sense when using such a server.
Default: ``False``
.. py:data:: SEND_FILE_MAX_AGE_DEFAULT
When serving files, set the cache control max age to this number of
seconds. Can be a :class:`datetime.timedelta` or an ``int``.
Override this value on a per-file basis using
:meth:`~flask.Flask.get_send_file_max_age` on the application or
blueprint.
If ``None``, ``send_file`` tells the browser to use conditional
requests will be used instead of a timed cache, which is usually
preferable.
Default: ``None``
.. py:data:: TRUSTED_HOSTS
Validate :attr:`.Request.host` and other attributes that use it against
these trusted values. Raise a :exc:`~werkzeug.exceptions.SecurityError` if
the host is invalid, which results in a 400 error. If it is ``None``, all
hosts are valid. Each value is either an exact match, or can start with
a dot ``.`` to match any subdomain.
Validation is done during routing against this value. ``before_request`` and
``after_request`` callbacks will still be called.
Default: ``None``
.. versionadded:: 3.1
.. py:data:: SERVER_NAME
Inform the application what host and port it is bound to.
Must be set if ``subdomain_matching`` is enabled, to be able to extract the
subdomain from the request.
Must be set for ``url_for`` to generate external URLs outside of a
request context.
Default: ``None``
.. versionchanged:: 3.1
Does not restrict requests to only this domain, for both
``subdomain_matching`` and ``host_matching``.
.. versionchanged:: 1.0
Does not implicitly enable ``subdomain_matching``.
.. versionchanged:: 2.3
Does not affect ``SESSION_COOKIE_DOMAIN``.
.. py:data:: APPLICATION_ROOT
Inform the application what path it is mounted under by the application /
web server. This is used for generating URLs outside the context of a
request (inside a request, the dispatcher is responsible for setting
``SCRIPT_NAME`` instead; see :doc:`/patterns/appdispatch`
for examples of dispatch configuration).
Will be used for the session cookie path if ``SESSION_COOKIE_PATH`` is not
set.
Default: ``'/'``
.. py:data:: PREFERRED_URL_SCHEME
Use this scheme for generating external URLs when not in a request context.
Default: ``'http'``
.. py:data:: MAX_CONTENT_LENGTH
The maximum number of bytes that will be read during this request. If
this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge`
error is raised. If it is set to ``None``, no limit is enforced at the
Flask application level. However, if it is ``None`` and the request has no
``Content-Length`` header and the WSGI server does not indicate that it
terminates the stream, then no data is read to avoid an infinite stream.
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_content_length` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.
Default: ``None``
.. versionadded:: 0.6
.. py:data:: MAX_FORM_MEMORY_SIZE
The maximum size in bytes any non-file form field may be in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it is
set to ``None``, no limit is enforced at the Flask application level.
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_memory_parts` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.
Default: ``500_000``
.. versionadded:: 3.1
.. py:data:: MAX_FORM_PARTS
The maximum number of fields that may be present in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it
is set to ``None``, no limit is enforced at the Flask application level.
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_parts` to apply the limit to that specific view.
This should be set appropriately based on an application's or view's
specific needs.
Default: ``1_000``
.. versionadded:: 3.1
.. py:data:: TEMPLATES_AUTO_RELOAD
Reload templates when they are changed. If not set, it will be enabled in
debug mode.
Default: ``None``
.. py:data:: EXPLAIN_TEMPLATE_LOADING
Log debugging information tracing how a template file was loaded. This can
be useful to figure out why a template was not loaded or the wrong file
appears to be loaded.
Default: ``False``
.. py:data:: MAX_COOKIE_SIZE
Warn if cookie headers are larger than this many bytes. Defaults to
``4093``. Larger cookies may be silently ignored by browsers. Set to
``0`` to disable the warning.
.. py:data:: PROVIDE_AUTOMATIC_OPTIONS
Set to ``False`` to disable the automatic addition of OPTIONS
responses. This can be overridden per route by altering the
``provide_automatic_options`` attribute.
.. versionadded:: 0.4
``LOGGER_NAME``
.. versionadded:: 0.5
``SERVER_NAME``
.. versionadded:: 0.6
``MAX_CONTENT_LENGTH``
.. versionadded:: 0.7
``PROPAGATE_EXCEPTIONS``, ``PRESERVE_CONTEXT_ON_EXCEPTION``
.. versionadded:: 0.8
``TRAP_BAD_REQUEST_ERRORS``, ``TRAP_HTTP_EXCEPTIONS``,
``APPLICATION_ROOT``, ``SESSION_COOKIE_DOMAIN``,
``SESSION_COOKIE_PATH``, ``SESSION_COOKIE_HTTPONLY``,
``SESSION_COOKIE_SECURE``
.. versionadded:: 0.9
``PREFERRED_URL_SCHEME``
.. versionadded:: 0.10
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_PRETTYPRINT_REGULAR``
.. versionadded:: 0.11
``SESSION_REFRESH_EACH_REQUEST``, ``TEMPLATES_AUTO_RELOAD``,
``LOGGER_HANDLER_POLICY``, ``EXPLAIN_TEMPLATE_LOADING``
.. versionchanged:: 1.0
``LOGGER_NAME`` and ``LOGGER_HANDLER_POLICY`` were removed. See
:doc:`/logging` for information about configuration.
Added :data:`ENV` to reflect the :envvar:`FLASK_ENV` environment
variable.
Added :data:`SESSION_COOKIE_SAMESITE` to control the session
cookie's ``SameSite`` option.
Added :data:`MAX_COOKIE_SIZE` to control a warning from Werkzeug.
.. versionchanged:: 2.2
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
.. versionchanged:: 2.3
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
``JSONIFY_PRETTYPRINT_REGULAR`` were removed. The default ``app.json`` provider has
equivalent attributes instead.
.. versionchanged:: 2.3
``ENV`` was removed.
.. versionadded:: 3.10
Added :data:`PROVIDE_AUTOMATIC_OPTIONS` to control the default
addition of autogenerated OPTIONS responses.
Configuring from Python Files
-----------------------------
Configuration becomes more useful if you can store it in a separate file, ideally
located outside the actual application package. You can deploy your application, then
separately configure it for the specific deployment.
A common pattern is this::
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
This first loads the configuration from the
`yourapplication.default_settings` module and then overrides the values
with the contents of the file the :envvar:`YOURAPPLICATION_SETTINGS`
environment variable points to. This environment variable can be set
in the shell before starting the server:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Fish
.. code-block:: text
$ set -x YOURAPPLICATION_SETTINGS /path/to/settings.cfg
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: CMD
.. code-block:: text
> set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg
> flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Powershell
.. code-block:: text
> $env:YOURAPPLICATION_SETTINGS = "\path\to\settings.cfg"
> flask run
* Running on http://127.0.0.1:5000/
The configuration files themselves are actual Python files. Only values
in uppercase are actually stored in the config object later on. So make
sure to use uppercase letters for your config keys.
Here is an example of a configuration file::
# Example configuration
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
Make sure to load the configuration very early on, so that extensions have
the ability to access the configuration when starting up. There are other
methods on the config object as well to load from individual files. For a
complete reference, read the :class:`~flask.Config` object's
documentation.
Configuring from Data Files
---------------------------
It is also possible to load configuration from a file in a format of
your choice using :meth:`~flask.Config.from_file`. For example to load
from a TOML file:
.. code-block:: python
import tomllib
app.config.from_file("config.toml", load=tomllib.load, text=False)
Or from a JSON file:
.. code-block:: python
import json
app.config.from_file("config.json", load=json.load)
Configuring from Environment Variables
--------------------------------------
In addition to pointing to configuration files using environment
variables, you may find it useful (or necessary) to control your
configuration values directly from the environment. Flask can be
instructed to load all environment variables starting with a specific
prefix into the config using :meth:`~flask.Config.from_prefixed_env`.
Environment variables can be set in the shell before starting the
server:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f"
$ export FLASK_MAIL_ENABLED=false
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_SECRET_KEY "5f352379324c22463451387a0aec5d2f"
$ set -x FLASK_MAIL_ENABLED false
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: CMD
.. code-block:: text
> set FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f"
> set FLASK_MAIL_ENABLED=false
> flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_SECRET_KEY = "5f352379324c22463451387a0aec5d2f"
> $env:FLASK_MAIL_ENABLED = "false"
> flask run
* Running on http://127.0.0.1:5000/
The variables can then be loaded and accessed via the config with a key
equal to the environment variable name without the prefix i.e.
.. code-block:: python
app.config.from_prefixed_env()
app.config["SECRET_KEY"] # Is "5f352379324c22463451387a0aec5d2f"
The prefix is ``FLASK_`` by default. This is configurable via the
``prefix`` argument of :meth:`~flask.Config.from_prefixed_env`.
Values will be parsed to attempt to convert them to a more specific type
than strings. By default :func:`json.loads` is used, so any valid JSON
value is possible, including lists and dicts. This is configurable via
the ``loads`` argument of :meth:`~flask.Config.from_prefixed_env`.
When adding a boolean value with the default JSON parsing, only "true"
and "false", lowercase, are valid values. Keep in mind that any
non-empty string is considered ``True`` by Python.
It is possible to set keys in nested dictionaries by separating the
keys with double underscore (``__``). Any intermediate keys that don't
exist on the parent dict will be initialized to an empty dict.
.. code-block:: text
$ export FLASK_MYAPI__credentials__username=user123
.. code-block:: python
app.config["MYAPI"]["credentials"]["username"] # Is "user123"
On Windows, environment variable keys are always uppercase, therefore
the above example would end up as ``MYAPI__CREDENTIALS__USERNAME``.
For even more config loading features, including merging and
case-insensitive Windows support, try a dedicated library such as
Dynaconf_, which includes integration with Flask.
.. _Dynaconf: https://www.dynaconf.com/
Configuration Best Practices
----------------------------
The downside with the approach mentioned earlier is that it makes testing
a little harder. There is no single 100% solution for this problem in
general, but there are a couple of things you can keep in mind to improve
that experience:
1. Create your application in a function and register blueprints on it.
That way you can create multiple instances of your application with
different configurations attached which makes unit testing a lot
easier. You can use this to pass in configuration as needed.
2. Do not write code that needs the configuration at import time. If you
limit yourself to request-only accesses to the configuration you can
reconfigure the object later on as needed.
3. Make sure to load the configuration very early on, so that
extensions can access the configuration when calling ``init_app``.
.. _config-dev-prod:
Development / Production
------------------------
Most applications need more than one configuration. There should be at
least separate configurations for the production server and the one used
during development. The easiest way to handle this is to use a default
configuration that is always loaded and part of the version control, and a
separate configuration that overrides the values as necessary as mentioned
in the example above::
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
Then you just have to add a separate :file:`config.py` file and export
``YOURAPPLICATION_SETTINGS=/path/to/config.py`` and you are done. However
there are alternative ways as well. For example you could use imports or
subclassing.
What is very popular in the Django world is to make the import explicit in
the config file by adding ``from yourapplication.default_settings
import *`` to the top of the file and then overriding the changes by hand.
You could also inspect an environment variable like
``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc
and import different hard-coded files based on that.
An interesting pattern is also to use classes and inheritance for
configuration::
class Config(object):
TESTING = False
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DATABASE_URI = "sqlite:////tmp/foo.db"
class TestingConfig(Config):
DATABASE_URI = 'sqlite:///:memory:'
TESTING = True
To enable such a config you just have to call into
:meth:`~flask.Config.from_object`::
app.config.from_object('configmodule.ProductionConfig')
Note that :meth:`~flask.Config.from_object` does not instantiate the class
object. If you need to instantiate the class, such as to access a property,
then you must do so before calling :meth:`~flask.Config.from_object`::
from configmodule import ProductionConfig
app.config.from_object(ProductionConfig())
# Alternatively, import via string:
from werkzeug.utils import import_string
cfg = import_string('configmodule.ProductionConfig')()
app.config.from_object(cfg)
Instantiating the configuration object allows you to use ``@property`` in
your configuration classes::
class Config(object):
"""Base config, uses staging database server."""
TESTING = False
DB_SERVER = '192.168.1.56'
@property
def DATABASE_URI(self): # Note: all caps
return f"mysql://user@{self.DB_SERVER}/foo"
class ProductionConfig(Config):
"""Uses production database server."""
DB_SERVER = '192.168.19.32'
class DevelopmentConfig(Config):
DB_SERVER = 'localhost'
class TestingConfig(Config):
DB_SERVER = 'localhost'
DATABASE_URI = 'sqlite:///:memory:'
There are many different ways and it's up to you how you want to manage
your configuration files. However here a list of good recommendations:
- Keep a default configuration in version control. Either populate the
config with this default configuration or import it in your own
configuration files before overriding values.
- Use an environment variable to switch between the configurations.
This can be done from outside the Python interpreter and makes
development and deployment much easier because you can quickly and
easily switch between different configs without having to touch the
code at all. If you are working often on different projects you can
even create your own script for sourcing that activates a virtualenv
and exports the development configuration for you.
- Use a tool like `fabric`_ to push code and configuration separately
to the production server(s).
.. _fabric: https://www.fabfile.org/
.. _instance-folders:
Instance Folders
----------------
.. versionadded:: 0.8
Flask 0.8 introduces instance folders. Flask for a long time made it
possible to refer to paths relative to the application's folder directly
(via :attr:`Flask.root_path`). This was also how many developers loaded
configurations stored next to the application. Unfortunately however this
only works well if applications are not packages in which case the root
path refers to the contents of the package.
With Flask 0.8 a new attribute was introduced:
:attr:`Flask.instance_path`. It refers to a new concept called the
“instance folder”. The instance folder is designed to not be under
version control and be deployment specific. It's the perfect place to
drop things that either change at runtime or configuration files.
You can either explicitly provide the path of the instance folder when
creating the Flask application or you can let Flask autodetect the
instance folder. For explicit configuration use the `instance_path`
parameter::
app = Flask(__name__, instance_path='/path/to/instance/folder')
Please keep in mind that this path *must* be absolute when provided.
If the `instance_path` parameter is not provided the following default
locations are used:
- Uninstalled module::
/myapp.py
/instance
- Uninstalled package::
/myapp
/__init__.py
/instance
- Installed module or package::
$PREFIX/lib/pythonX.Y/site-packages/myapp
$PREFIX/var/myapp-instance
``$PREFIX`` is the prefix of your Python installation. This can be
``/usr`` or the path to your virtualenv. You can print the value of
``sys.prefix`` to see what the prefix is set to.
Since the config object provided loading of configuration files from
relative filenames we made it possible to change the loading via filenames
to be relative to the instance path if wanted. The behavior of relative
paths in config files can be flipped between “relative to the application
root” (the default) to “relative to instance folder” via the
`instance_relative_config` switch to the application constructor::
app = Flask(__name__, instance_relative_config=True)
Here is a full example of how to configure Flask to preload the config
from a module and then override the config from a file in the instance
folder if it exists::
app = Flask(__name__, instance_relative_config=True)
app.config.from_object('yourapplication.default_settings')
app.config.from_pyfile('application.cfg', silent=True)
The path to the instance folder can be found via the
:attr:`Flask.instance_path`. Flask also provides a shortcut to open a
file from the instance folder with :meth:`Flask.open_instance_resource`.
Example usage for both::
filename = os.path.join(app.instance_path, 'application.cfg')
with open(filename) as f:
config = f.read()
# or via open_instance_resource:
with app.open_instance_resource('application.cfg') as f:
config = f.read()

@ -0,0 +1,8 @@
Contributing
============
See the Pallets `detailed contributing documentation <contrib_>`_ for many ways
to contribute, including reporting issues, requesting features, asking or
answering questions, and making PRs.
.. _contrib: https://palletsprojects.com/contributing/

@ -0,0 +1,99 @@
Debugging Application Errors
============================
In Production
-------------
**Do not run the development server, or enable the built-in debugger, in
a production environment.** The debugger allows executing arbitrary
Python code from the browser. It's protected by a pin, but that should
not be relied on for security.
Use an error logging tool, such as Sentry, as described in
:ref:`error-logging-tools`, or enable logging and notifications as
described in :doc:`/logging`.
If you have access to the server, you could add some code to start an
external debugger if ``request.remote_addr`` matches your IP. Some IDE
debuggers also have a remote mode so breakpoints on the server can be
interacted with locally. Only enable a debugger temporarily.
The Built-In Debugger
---------------------
The built-in Werkzeug development server provides a debugger which shows
an interactive traceback in the browser when an unhandled error occurs
during a request. This debugger should only be used during development.
.. image:: _static/debugger.png
:align: center
:class: screenshot
:alt: screenshot of debugger in action
.. warning::
The debugger allows executing arbitrary Python code from the
browser. It is protected by a pin, but still represents a major
security risk. Do not run the development server or debugger in a
production environment.
The debugger is enabled by default when the development server is run in debug mode.
.. code-block:: text
$ flask --app hello run --debug
When running from Python code, passing ``debug=True`` enables debug mode, which is
mostly equivalent.
.. code-block:: python
app.run(debug=True)
:doc:`/server` and :doc:`/cli` have more information about running the debugger and
debug mode. More information about the debugger can be found in the `Werkzeug
documentation <https://werkzeug.palletsprojects.com/debug/>`__.
External Debuggers
------------------
External debuggers, such as those provided by IDEs, can offer a more
powerful debugging experience than the built-in debugger. They can also
be used to step through code during a request before an error is raised,
or if no error is raised. Some even have a remote mode so you can debug
code running on another machine.
When using an external debugger, the app should still be in debug mode, otherwise Flask
turns unhandled errors into generic 500 error pages. However, the built-in debugger and
reloader should be disabled so they don't interfere with the external debugger.
.. code-block:: text
$ flask --app hello run --debug --no-debugger --no-reload
When running from Python:
.. code-block:: python
app.run(debug=True, use_debugger=False, use_reloader=False)
Disabling these isn't required, an external debugger will continue to work with the
following caveats.
- If the built-in debugger is not disabled, it will catch unhandled exceptions before
the external debugger can.
- If the reloader is not disabled, it could cause an unexpected reload if code changes
during a breakpoint.
- The development server will still catch unhandled exceptions if the built-in
debugger is disabled, otherwise it would crash on any error. If you want that (and
usually you don't) pass ``passthrough_errors=True`` to ``app.run``.
.. code-block:: python
app.run(
debug=True, passthrough_errors=True,
use_debugger=False, use_reloader=False
)

@ -0,0 +1,66 @@
Apache httpd
============
`Apache httpd`_ is a fast, production level HTTP server. When serving
your application with one of the WSGI servers listed in :doc:`index`, it
is often good or necessary to put a dedicated HTTP server in front of
it. This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
httpd can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running httpd itself is outside
the scope of this doc. This page outlines the basics of configuring
httpd to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _Apache httpd: https://httpd.apache.org/
Domain Name
-----------
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your ``hosts`` file, located at
``/etc/hosts`` on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with ``.localhost`` like this without adding it to the ``hosts``
file.
.. code-block:: python
:caption: ``/etc/hosts``
127.0.0.1 hello.localhost
Configuration
-------------
The httpd configuration is located at ``/etc/httpd/conf/httpd.conf`` on
Linux. It may be different depending on your operating system. Check the
docs and look for ``httpd.conf``.
Remove or comment out any existing ``DocumentRoot`` directive. Add the
config lines below. We'll assume the WSGI server is listening locally at
``http://127.0.0.1:8000``.
.. code-block:: apache
:caption: ``/etc/httpd/conf/httpd.conf``
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyPass / http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto http
RequestHeader set X-Forwarded-Prefix /
The ``LoadModule`` lines might already exist. If so, make sure they are
uncommented instead of adding them manually.
Then :doc:`proxy_fix` so that your application uses the ``X-Forwarded``
headers. ``X-Forwarded-For`` and ``X-Forwarded-Host`` are automatically
set by ``ProxyPass``.

@ -0,0 +1,27 @@
ASGI
====
If you'd like to use an ASGI server you will need to utilise WSGI to
ASGI middleware. The asgiref
`WsgiToAsgi <https://github.com/django/asgiref#wsgi-to-asgi-adapter>`_
adapter is recommended as it integrates with the event loop used for
Flask's :ref:`async_await` support. You can use the adapter by
wrapping the Flask app,
.. code-block:: python
from asgiref.wsgi import WsgiToAsgi
from flask import Flask
app = Flask(__name__)
...
asgi_app = WsgiToAsgi(app)
and then serving the ``asgi_app`` with the ASGI server, e.g. using
`Hypercorn <https://github.com/pgjones/hypercorn>`_,
.. sourcecode:: text
$ hypercorn module:asgi_app

@ -0,0 +1,80 @@
eventlet
========
Prefer using :doc:`gunicorn` with eventlet workers rather than using
`eventlet`_ directly. Gunicorn provides a much more configurable and
production-tested server.
`eventlet`_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses `greenlet`_ to enable task
switching without writing ``async/await`` or using ``asyncio``.
:doc:`gevent` is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
eventlet provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use eventlet in
your own code to see any benefit to using the server.
.. _eventlet: https://eventlet.net/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
----------
When using eventlet, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install
``eventlet``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install eventlet
Running
-------
To use eventlet to serve your application, write a script that imports
its ``wsgi.server``, as well as your app or app factory.
.. code-block:: python
:caption: ``wsgi.py``
import eventlet
from eventlet import wsgi
from hello import create_app
app = create_app()
wsgi.server(eventlet.listen(("127.0.0.1", 8000)), app)
.. code-block:: text
$ python wsgi.py
(x) wsgi starting up on http://127.0.0.1:8000
Binding Externally
------------------
eventlet should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of eventlet.
You can bind to all external IPs on a non-privileged port by using
``0.0.0.0`` in the server arguments shown in the previous section.
Don't do this when using a reverse proxy setup, otherwise it will be
possible to bypass the proxy.
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.

@ -0,0 +1,80 @@
gevent
======
Prefer using :doc:`gunicorn` or :doc:`uwsgi` with gevent workers rather
than using `gevent`_ directly. Gunicorn and uWSGI provide much more
configurable and production-tested servers.
`gevent`_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses `greenlet`_ to enable task
switching without writing ``async/await`` or using ``asyncio``.
:doc:`eventlet` is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
gevent provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use gevent in your
own code to see any benefit to using the server.
.. _gevent: https://www.gevent.org/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
----------
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install ``gevent``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install gevent
Running
-------
To use gevent to serve your application, write a script that imports its
``WSGIServer``, as well as your app or app factory.
.. code-block:: python
:caption: ``wsgi.py``
from gevent.pywsgi import WSGIServer
from hello import create_app
app = create_app()
http_server = WSGIServer(("127.0.0.1", 8000), app)
http_server.serve_forever()
.. code-block:: text
$ python wsgi.py
No output is shown when the server starts.
Binding Externally
------------------
gevent should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of gevent.
You can bind to all external IPs on a non-privileged port by using
``0.0.0.0`` in the server arguments shown in the previous section. Don't
do this when using a reverse proxy setup, otherwise it will be possible
to bypass the proxy.
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.

@ -0,0 +1,130 @@
Gunicorn
========
`Gunicorn`_ is a pure Python WSGI server with simple configuration and
multiple worker implementations for performance tuning.
* It tends to integrate easily with hosting platforms.
* It does not support Windows (but does run on WSL).
* It is easy to install as it does not require additional dependencies
or compilation.
* It has built-in async worker support using gevent or eventlet.
This page outlines the basics of running Gunicorn. Be sure to read its
`documentation`_ and use ``gunicorn --help`` to understand what features
are available.
.. _Gunicorn: https://gunicorn.org/
.. _documentation: https://docs.gunicorn.org/
Installing
----------
Gunicorn is easy to install, as it does not require external
dependencies or compilation. It runs on Windows only under WSL.
Create a virtualenv, install your application, then install
``gunicorn``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install gunicorn
Running
-------
The only required argument to Gunicorn tells it how to load your Flask
application. The syntax is ``{module_import}:{app_variable}``.
``module_import`` is the dotted import name to the module with your
application. ``app_variable`` is the variable with the application. It
can also be a function call (with any arguments) if you're using the
app factory pattern.
.. code-block:: text
# equivalent to 'from hello import app'
$ gunicorn -w 4 'hello:app'
# equivalent to 'from hello import create_app; create_app()'
$ gunicorn -w 4 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: sync
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: x
The ``-w`` option specifies the number of processes to run; a starting
value could be ``CPU * 2``. The default is only 1 worker, which is
probably not what you want for the default worker type.
Logs for each request aren't shown by default, only worker info and
errors are shown. To show access logs on stdout, use the
``--access-logfile=-`` option.
Binding Externally
------------------
Gunicorn should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of Gunicorn.
You can bind to all external IPs on a non-privileged port using the
``-b 0.0.0.0`` option. Don't do this when using a reverse proxy setup,
otherwise it will be possible to bypass the proxy.
.. code-block:: text
$ gunicorn -w 4 -b 0.0.0.0 'hello:create_app()'
Listening at: http://0.0.0.0:8000 (x)
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.
Async with gevent or eventlet
-----------------------------
The default sync worker is appropriate for many use cases. If you need
asynchronous support, Gunicorn provides workers using either `gevent`_
or `eventlet`_. This is not the same as Python's ``async/await``, or the
ASGI server spec. You must actually use gevent/eventlet in your own code
to see any benefit to using the workers.
When using either gevent or eventlet, greenlet>=1.0 is required,
otherwise context locals such as ``request`` will not work as expected.
When using PyPy, PyPy>=7.3.7 is required.
To use gevent:
.. code-block:: text
$ gunicorn -k gevent 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: gevent
Booting worker with pid: x
To use eventlet:
.. code-block:: text
$ gunicorn -k eventlet 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: eventlet
Booting worker with pid: x
.. _gevent: https://www.gevent.org/
.. _eventlet: https://eventlet.net/

@ -0,0 +1,79 @@
Deploying to Production
=======================
After developing your application, you'll want to make it available
publicly to other users. When you're developing locally, you're probably
using the built-in development server, debugger, and reloader. These
should not be used in production. Instead, you should use a dedicated
WSGI server or hosting platform, some of which will be described here.
"Production" means "not development", which applies whether you're
serving your application publicly to millions of users or privately /
locally to a single user. **Do not use the development server when
deploying to production. It is intended for use only during local
development. It is not designed to be particularly secure, stable, or
efficient.**
Self-Hosted Options
-------------------
Flask is a WSGI *application*. A WSGI *server* is used to run the
application, converting incoming HTTP requests to the standard WSGI
environ, and converting outgoing WSGI responses to HTTP responses.
The primary goal of these docs is to familiarize you with the concepts
involved in running a WSGI application using a production WSGI server
and HTTP server. There are many WSGI servers and HTTP servers, with many
configuration possibilities. The pages below discuss the most common
servers, and show the basics of running each one. The next section
discusses platforms that can manage this for you.
.. toctree::
:maxdepth: 1
gunicorn
waitress
mod_wsgi
uwsgi
gevent
eventlet
asgi
WSGI servers have HTTP servers built-in. However, a dedicated HTTP
server may be safer, more efficient, or more capable. Putting an HTTP
server in front of the WSGI server is called a "reverse proxy."
.. toctree::
:maxdepth: 1
proxy_fix
nginx
apache-httpd
This list is not exhaustive, and you should evaluate these and other
servers based on your application's needs. Different servers will have
different capabilities, configuration, and support.
Hosting Platforms
-----------------
There are many services available for hosting web applications without
needing to maintain your own server, networking, domain, etc. Some
services may have a free tier up to a certain time or bandwidth. Many of
these services use one of the WSGI servers described above, or a similar
interface. The links below are for some of the most common platforms,
which have instructions for Flask, WSGI, or Python.
- `PythonAnywhere <https://help.pythonanywhere.com/pages/Flask/>`_
- `Google App Engine <https://cloud.google.com/appengine/docs/standard/python3/building-app>`_
- `Google Cloud Run <https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service>`_
- `AWS Elastic Beanstalk <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html>`_
- `Microsoft Azure <https://docs.microsoft.com/en-us/azure/app-service/quickstart-python>`_
This list is not exhaustive, and you should evaluate these and other
services based on your application's needs. Different services will have
different capabilities, configuration, pricing, and support.
You'll probably need to :doc:`proxy_fix` when using most hosting
platforms.

@ -0,0 +1,94 @@
mod_wsgi
========
`mod_wsgi`_ is a WSGI server integrated with the `Apache httpd`_ server.
The modern `mod_wsgi-express`_ command makes it easy to configure and
start the server without needing to write Apache httpd configuration.
* Tightly integrated with Apache httpd.
* Supports Windows directly.
* Requires a compiler and the Apache development headers to install.
* Does not require a reverse proxy setup.
This page outlines the basics of running mod_wsgi-express, not the more
complex installation and configuration with httpd. Be sure to read the
`mod_wsgi-express`_, `mod_wsgi`_, and `Apache httpd`_ documentation to
understand what features are available.
.. _mod_wsgi-express: https://pypi.org/project/mod-wsgi/
.. _mod_wsgi: https://modwsgi.readthedocs.io/
.. _Apache httpd: https://httpd.apache.org/
Installing
----------
Installing mod_wsgi requires a compiler and the Apache server and
development headers installed. You will get an error if they are not.
How to install them depends on the OS and package manager that you use.
Create a virtualenv, install your application, then install
``mod_wsgi``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install mod_wsgi
Running
-------
The only argument to ``mod_wsgi-express`` specifies a script containing
your Flask application, which must be called ``application``. You can
write a small script to import your app with this name, or to create it
if using the app factory pattern.
.. code-block:: python
:caption: ``wsgi.py``
from hello import app
application = app
.. code-block:: python
:caption: ``wsgi.py``
from hello import create_app
application = create_app()
Now run the ``mod_wsgi-express start-server`` command.
.. code-block:: text
$ mod_wsgi-express start-server wsgi.py --processes 4
The ``--processes`` option specifies the number of worker processes to
run; a starting value could be ``CPU * 2``.
Logs for each request aren't show in the terminal. If an error occurs,
its information is written to the error log file shown when starting the
server.
Binding Externally
------------------
Unlike the other WSGI servers in these docs, mod_wsgi can be run as
root to bind to privileged ports like 80 and 443. However, it must be
configured to drop permissions to a different user and group for the
worker processes.
For example, if you created a ``hello`` user and group, you should
install your virtualenv and application as that user, then tell
mod_wsgi to drop to that user after starting.
.. code-block:: text
$ sudo /home/hello/.venv/bin/mod_wsgi-express start-server \
/home/hello/wsgi.py \
--user hello --group hello --port 80 --processes 4

@ -0,0 +1,69 @@
nginx
=====
`nginx`_ is a fast, production level HTTP server. When serving your
application with one of the WSGI servers listed in :doc:`index`, it is
often good or necessary to put a dedicated HTTP server in front of it.
This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
Nginx can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running Nginx itself is outside
the scope of this doc. This page outlines the basics of configuring
Nginx to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _nginx: https://nginx.org/
Domain Name
-----------
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your ``hosts`` file, located at
``/etc/hosts`` on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with ``.localhost`` like this without adding it to the ``hosts``
file.
.. code-block:: python
:caption: ``/etc/hosts``
127.0.0.1 hello.localhost
Configuration
-------------
The nginx configuration is located at ``/etc/nginx/nginx.conf`` on
Linux. It may be different depending on your operating system. Check the
docs and look for ``nginx.conf``.
Remove or comment out any existing ``server`` section. Add a ``server``
section and use the ``proxy_pass`` directive to point to the address the
WSGI server is listening on. We'll assume the WSGI server is listening
locally at ``http://127.0.0.1:8000``.
.. code-block:: nginx
:caption: ``/etc/nginx.conf``
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /;
}
}
Then :doc:`proxy_fix` so that your application uses these headers.

@ -0,0 +1,33 @@
Tell Flask it is Behind a Proxy
===============================
When using a reverse proxy, or many Python hosting platforms, the proxy
will intercept and forward all external requests to the local WSGI
server.
From the WSGI server and Flask application's perspectives, requests are
now coming from the HTTP server to the local address, rather than from
the remote address to the external server address.
HTTP servers should set ``X-Forwarded-`` headers to pass on the real
values to the application. The application can then be told to trust and
use those values by wrapping it with the
:doc:`werkzeug:middleware/proxy_fix` middleware provided by Werkzeug.
This middleware should only be used if the application is actually
behind a proxy, and should be configured with the number of proxies that
are chained in front of it. Not all proxies set all the headers. Since
incoming headers can be faked, you must set how many proxies are setting
each header so the middleware knows what to trust.
.. code-block:: python
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)
Remember, only apply this middleware if you are behind a proxy, and set
the correct number of proxies that set each header. It can be a security
issue if you get this configuration wrong.

@ -0,0 +1,145 @@
uWSGI
=====
`uWSGI`_ is a fast, compiled server suite with extensive configuration
and capabilities beyond a basic server.
* It can be very performant due to being a compiled program.
* It is complex to configure beyond the basic application, and has so
many options that it can be difficult for beginners to understand.
* It does not support Windows (but does run on WSL).
* It requires a compiler to install in some cases.
This page outlines the basics of running uWSGI. Be sure to read its
documentation to understand what features are available.
.. _uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/
Installing
----------
uWSGI has multiple ways to install it. The most straightforward is to
install the ``pyuwsgi`` package, which provides precompiled wheels for
common platforms. However, it does not provide SSL support, which can be
provided with a reverse proxy instead.
Create a virtualenv, install your application, then install ``pyuwsgi``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install pyuwsgi
If you have a compiler available, you can install the ``uwsgi`` package
instead. Or install the ``pyuwsgi`` package from sdist instead of wheel.
Either method will include SSL support.
.. code-block:: text
$ pip install uwsgi
# or
$ pip install --no-binary pyuwsgi pyuwsgi
Running
-------
The most basic way to run uWSGI is to tell it to start an HTTP server
and import your application.
.. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master -p 4 -w hello:app
*** Starting uWSGI 2.0.20 (64bit) on [x] ***
*** Operational MODE: preforking ***
mounting hello:app on /
spawned uWSGI master process (pid: x)
spawned uWSGI worker 1 (pid: x, cores: 1)
spawned uWSGI worker 2 (pid: x, cores: 1)
spawned uWSGI worker 3 (pid: x, cores: 1)
spawned uWSGI worker 4 (pid: x, cores: 1)
spawned uWSGI http 1 (pid: x)
If you're using the app factory pattern, you'll need to create a small
Python file to create the app, then point uWSGI at that.
.. code-block:: python
:caption: ``wsgi.py``
from hello import create_app
app = create_app()
.. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master -p 4 -w wsgi:app
The ``--http`` option starts an HTTP server at 127.0.0.1 port 8000. The
``--master`` option specifies the standard worker manager. The ``-p``
option starts 4 worker processes; a starting value could be ``CPU * 2``.
The ``-w`` option tells uWSGI how to import your application
Binding Externally
------------------
uWSGI should not be run as root with the configuration shown in this doc
because it would cause your application code to run as root, which is
not secure. However, this means it will not be possible to bind to port
80 or 443. Instead, a reverse proxy such as :doc:`nginx` or
:doc:`apache-httpd` should be used in front of uWSGI. It is possible to
run uWSGI as root securely, but that is beyond the scope of this doc.
uWSGI has optimized integration with `Nginx uWSGI`_ and
`Apache mod_proxy_uwsgi`_, and possibly other servers, instead of using
a standard HTTP proxy. That configuration is beyond the scope of this
doc, see the links for more information.
.. _Nginx uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html
.. _Apache mod_proxy_uwsgi: https://uwsgi-docs.readthedocs.io/en/latest/Apache.html#mod-proxy-uwsgi
You can bind to all external IPs on a non-privileged port using the
``--http 0.0.0.0:8000`` option. Don't do this when using a reverse proxy
setup, otherwise it will be possible to bypass the proxy.
.. code-block:: text
$ uwsgi --http 0.0.0.0:8000 --master -p 4 -w wsgi:app
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.
Async with gevent
-----------------
The default sync worker is appropriate for many use cases. If you need
asynchronous support, uWSGI provides a `gevent`_ worker. This is not the
same as Python's ``async/await``, or the ASGI server spec. You must
actually use gevent in your own code to see any benefit to using the
worker.
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
.. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master --gevent 100 -w wsgi:app
*** Starting uWSGI 2.0.20 (64bit) on [x] ***
*** Operational MODE: async ***
mounting hello:app on /
spawned uWSGI master process (pid: x)
spawned uWSGI worker 1 (pid: x, cores: 100)
spawned uWSGI http 1 (pid: x)
*** running gevent loop engine [addr:x] ***
.. _gevent: https://www.gevent.org/

@ -0,0 +1,75 @@
Waitress
========
`Waitress`_ is a pure Python WSGI server.
* It is easy to configure.
* It supports Windows directly.
* It is easy to install as it does not require additional dependencies
or compilation.
* It does not support streaming requests, full request data is always
buffered.
* It uses a single process with multiple thread workers.
This page outlines the basics of running Waitress. Be sure to read its
documentation and ``waitress-serve --help`` to understand what features
are available.
.. _Waitress: https://docs.pylonsproject.org/projects/waitress/
Installing
----------
Create a virtualenv, install your application, then install
``waitress``.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install waitress
Running
-------
The only required argument to ``waitress-serve`` tells it how to load
your Flask application. The syntax is ``{module}:{app}``. ``module`` is
the dotted import name to the module with your application. ``app`` is
the variable with the application. If you're using the app factory
pattern, use ``--call {module}:{factory}`` instead.
.. code-block:: text
# equivalent to 'from hello import app'
$ waitress-serve --host 127.0.0.1 hello:app
# equivalent to 'from hello import create_app; create_app()'
$ waitress-serve --host 127.0.0.1 --call hello:create_app
Serving on http://127.0.0.1:8080
The ``--host`` option binds the server to local ``127.0.0.1`` only.
Logs for each request aren't shown, only errors are shown. Logging can
be configured through the Python interface instead of the command line.
Binding Externally
------------------
Waitress should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of Waitress.
You can bind to all external IPs on a non-privileged port by not
specifying the ``--host`` option. Don't do this when using a reverse
proxy setup, otherwise it will be possible to bypass the proxy.
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.

@ -0,0 +1,229 @@
Design Decisions in Flask
=========================
If you are curious why Flask does certain things the way it does and not
differently, this section is for you. This should give you an idea about
some of the design decisions that may appear arbitrary and surprising at
first, especially in direct comparison with other frameworks.
The Explicit Application Object
-------------------------------
A Python web application based on WSGI has to have one central callable
object that implements the actual application. In Flask this is an
instance of the :class:`~flask.Flask` class. Each Flask application has
to create an instance of this class itself and pass it the name of the
module, but why can't Flask do that itself?
Without such an explicit application object the following code::
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World!'
Would look like this instead::
from hypothetical_flask import route
@route('/')
def index():
return 'Hello World!'
There are three major reasons for this. The most important one is that
implicit application objects require that there may only be one instance at
the time. There are ways to fake multiple applications with a single
application object, like maintaining a stack of applications, but this
causes some problems I won't outline here in detail. Now the question is:
when does a microframework need more than one application at the same
time? A good example for this is unit testing. When you want to test
something it can be very helpful to create a minimal application to test
specific behavior. When the application object is deleted everything it
allocated will be freed again.
Another thing that becomes possible when you have an explicit object lying
around in your code is that you can subclass the base class
(:class:`~flask.Flask`) to alter specific behavior. This would not be
possible without hacks if the object were created ahead of time for you
based on a class that is not exposed to you.
But there is another very important reason why Flask depends on an
explicit instantiation of that class: the package name. Whenever you
create a Flask instance you usually pass it `__name__` as package name.
Flask depends on that information to properly load resources relative
to your module. With Python's outstanding support for reflection it can
then access the package to figure out where the templates and static files
are stored (see :meth:`~flask.Flask.open_resource`). Now obviously there
are frameworks around that do not need any configuration and will still be
able to load templates relative to your application module. But they have
to use the current working directory for that, which is a very unreliable
way to determine where the application is. The current working directory
is process-wide and if you are running multiple applications in one
process (which could happen in a webserver without you knowing) the paths
will be off. Worse: many webservers do not set the working directory to
the directory of your application but to the document root which does not
have to be the same folder.
The third reason is "explicit is better than implicit". That object is
your WSGI application, you don't have to remember anything else. If you
want to apply a WSGI middleware, just wrap it and you're done (though
there are better ways to do that so that you do not lose the reference
to the application object :meth:`~flask.Flask.wsgi_app`).
Furthermore this design makes it possible to use a factory function to
create the application which is very helpful for unit testing and similar
things (:doc:`/patterns/appfactories`).
The Routing System
------------------
Flask uses the Werkzeug routing system which was designed to
automatically order routes by complexity. This means that you can declare
routes in arbitrary order and they will still work as expected. This is a
requirement if you want to properly implement decorator based routing
since decorators could be fired in undefined order when the application is
split into multiple modules.
Another design decision with the Werkzeug routing system is that routes
in Werkzeug try to ensure that URLs are unique. Werkzeug will go quite far
with that in that it will automatically redirect to a canonical URL if a route
is ambiguous.
One Template Engine
-------------------
Flask decides on one template engine: Jinja. Why doesn't Flask have a
pluggable template engine interface? You can obviously use a different
template engine, but Flask will still configure Jinja for you. While
that limitation that Jinja is *always* configured will probably go away,
the decision to bundle one template engine and use that will not.
Template engines are like programming languages and each of those engines
has a certain understanding about how things work. On the surface they
all work the same: you tell the engine to evaluate a template with a set
of variables and take the return value as string.
But that's about where similarities end. Jinja for example has an
extensive filter system, a certain way to do template inheritance,
support for reusable blocks (macros) that can be used from inside
templates and also from Python code, supports iterative template
rendering, configurable syntax and more. On the other hand an engine
like Genshi is based on XML stream evaluation, template inheritance by
taking the availability of XPath into account and more. Mako on the
other hand treats templates similar to Python modules.
When it comes to connecting a template engine with an application or
framework there is more than just rendering templates. For instance,
Flask uses Jinja's extensive autoescaping support. Also it provides
ways to access macros from Jinja templates.
A template abstraction layer that would not take the unique features of
the template engines away is a science on its own and a too large
undertaking for a microframework like Flask.
Furthermore extensions can then easily depend on one template language
being present. You can easily use your own templating language, but an
extension could still depend on Jinja itself.
What does "micro" mean?
-----------------------
“Micro” does not mean that your whole web application has to fit into a single
Python file (although it certainly can), nor does it mean that Flask is lacking
in functionality. The "micro" in microframework means Flask aims to keep the
core simple but extensible. Flask won't make many decisions for you, such as
what database to use. Those decisions that it does make, such as what
templating engine to use, are easy to change. Everything else is up to you, so
that Flask can be everything you need and nothing you don't.
By default, Flask does not include a database abstraction layer, form
validation or anything else where different libraries already exist that can
handle that. Instead, Flask supports extensions to add such functionality to
your application as if it was implemented in Flask itself. Numerous extensions
provide database integration, form validation, upload handling, various open
authentication technologies, and more. Flask may be "micro", but it's ready for
production use on a variety of needs.
Why does Flask call itself a microframework and yet it depends on two
libraries (namely Werkzeug and Jinja). Why shouldn't it? If we look
over to the Ruby side of web development there we have a protocol very
similar to WSGI. Just that it's called Rack there, but besides that it
looks very much like a WSGI rendition for Ruby. But nearly all
applications in Ruby land do not work with Rack directly, but on top of a
library with the same name. This Rack library has two equivalents in
Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but
from my understanding it's sort of deprecated in favour of WebOb. The
development of WebOb and Werkzeug started side by side with similar ideas
in mind: be a good implementation of WSGI for other applications to take
advantage.
Flask is a framework that takes advantage of the work already done by
Werkzeug to properly interface WSGI (which can be a complex task at
times). Thanks to recent developments in the Python package
infrastructure, packages with dependencies are no longer an issue and
there are very few reasons against having libraries that depend on others.
Context Locals
--------------
Flask uses special context locals and proxies to provide access to the
current app and request data to any code running during a request, CLI command,
etc. Context locals are specific to the worker handling the activity, such as a
thread, process, coroutine, or greenlet.
The context and proxies help solve two development issues: circular imports, and
passing around global data. :data:`.current_app` can be used to access the
application object without needing to import the app object directly, avoiding
circular import issues. :data:`.request`, :data:`.session`, and :data:`.g` can
be imported to access the current data for the request, rather than needing to
pass them as arguments through every single function in your project.
Async/await and ASGI support
----------------------------
Flask supports ``async`` coroutines for view functions by executing the
coroutine on a separate thread instead of using an event loop on the
main thread as an async-first (ASGI) framework would. This is necessary
for Flask to remain backwards compatible with extensions and code built
before ``async`` was introduced into Python. This compromise introduces
a performance cost compared with the ASGI frameworks, due to the
overhead of the threads.
Due to how tied to WSGI Flask's code is, it's not clear if it's possible
to make the ``Flask`` class support ASGI and WSGI at the same time. Work
is currently being done in Werkzeug to work with ASGI, which may
eventually enable support in Flask as well.
See :doc:`/async-await` for more discussion.
What Flask is, What Flask is Not
--------------------------------
Flask will never have a database layer. It will not have a form library
or anything else in that direction. Flask itself just bridges to Werkzeug
to implement a proper WSGI application and to Jinja to handle templating.
It also binds to a few common standard library packages such as logging.
Everything else is up for extensions.
Why is this the case? Because people have different preferences and
requirements and Flask could not meet those if it would force any of this
into the core. The majority of web applications will need a template
engine in some sort. However not every application needs a SQL database.
As your codebase grows, you are free to make the design decisions appropriate
for your project. Flask will continue to provide a very simple glue layer to
the best that Python has to offer. You can implement advanced patterns in
SQLAlchemy or another database tool, introduce non-relational data persistence
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
the Python web interface.
The idea of Flask is to build a good foundation for all applications.
Everything else is up to you or extensions.

@ -0,0 +1,523 @@
Handling Application Errors
===========================
Applications fail, servers fail. Sooner or later you will see an exception
in production. Even if your code is 100% correct, you will still see
exceptions from time to time. Why? Because everything else involved will
fail. Here are some situations where perfectly fine code can lead to server
errors:
- the client terminated the request early and the application was still
reading from the incoming data
- the database server was overloaded and could not handle the query
- a filesystem is full
- a harddrive crashed
- a backend server overloaded
- a programming error in a library you are using
- network connection of the server to another system failed
And that's just a small sample of issues you could be facing. So how do we
deal with that sort of problem? By default if your application runs in
production mode, and an exception is raised Flask will display a very simple
page for you and log the exception to the :attr:`~flask.Flask.logger`.
But there is more you can do, and we will cover some better setups to deal
with errors including custom exceptions and 3rd party tools.
.. _error-logging-tools:
Error Logging Tools
-------------------
Sending error mails, even if just for critical ones, can become
overwhelming if enough users are hitting the error and log files are
typically never looked at. This is why we recommend using `Sentry
<https://sentry.io/>`_ for dealing with application errors. It's
available as a source-available project `on GitHub
<https://github.com/getsentry/sentry>`_ and is also available as a `hosted version
<https://sentry.io/signup/>`_ which you can try for free. Sentry
aggregates duplicate errors, captures the full stack trace and local
variables for debugging, and sends you mails based on new errors or
frequency thresholds.
To use Sentry you need to install the ``sentry-sdk`` client with extra
``flask`` dependencies.
.. code-block:: text
$ pip install sentry-sdk[flask]
And then add this to your Flask app:
.. code-block:: python
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init('YOUR_DSN_HERE', integrations=[FlaskIntegration()])
The ``YOUR_DSN_HERE`` value needs to be replaced with the DSN value you
get from your Sentry installation.
After installation, failures leading to an Internal Server Error
are automatically reported to Sentry and from there you can
receive error notifications.
See also:
- Sentry also supports catching errors from a worker queue
(RQ, Celery, etc.) in a similar fashion. See the `Python SDK docs
<https://docs.sentry.io/platforms/python/>`__ for more information.
- `Flask-specific documentation <https://docs.sentry.io/platforms/python/guides/flask/>`__
Error Handlers
--------------
When an error occurs in Flask, an appropriate `HTTP status code
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Status>`__ will be
returned. 400-499 indicate errors with the client's request data, or
about the data requested. 500-599 indicate errors with the server or
application itself.
You might want to show custom error pages to the user when an error occurs.
This can be done by registering error handlers.
An error handler is a function that returns a response when a type of error is
raised, similar to how a view is a function that returns a response when a
request URL is matched. It is passed the instance of the error being handled,
which is most likely a :exc:`~werkzeug.exceptions.HTTPException`.
The status code of the response will not be set to the handler's code. Make
sure to provide the appropriate HTTP status code when returning a response from
a handler.
Registering
```````````
Register handlers by decorating a function with
:meth:`~flask.Flask.errorhandler`. Or use
:meth:`~flask.Flask.register_error_handler` to register the function later.
Remember to set the error code when returning the response.
.. code-block:: python
@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
return 'bad request!', 400
# or, without the decorator
app.register_error_handler(400, handle_bad_request)
:exc:`werkzeug.exceptions.HTTPException` subclasses like
:exc:`~werkzeug.exceptions.BadRequest` and their HTTP codes are interchangeable
when registering handlers. (``BadRequest.code == 400``)
Non-standard HTTP codes cannot be registered by code because they are not known
by Werkzeug. Instead, define a subclass of
:class:`~werkzeug.exceptions.HTTPException` with the appropriate code and
register and raise that exception class.
.. code-block:: python
class InsufficientStorage(werkzeug.exceptions.HTTPException):
code = 507
description = 'Not enough storage space.'
app.register_error_handler(InsufficientStorage, handle_507)
raise InsufficientStorage()
Handlers can be registered for any exception class, not just
:exc:`~werkzeug.exceptions.HTTPException` subclasses or HTTP status
codes. Handlers can be registered for a specific class, or for all subclasses
of a parent class.
Handling
````````
When building a Flask application you *will* run into exceptions. If some part
of your code breaks while handling a request (and you have no error handlers
registered), a "500 Internal Server Error"
(:exc:`~werkzeug.exceptions.InternalServerError`) will be returned by default.
Similarly, "404 Not Found"
(:exc:`~werkzeug.exceptions.NotFound`) error will occur if a request is sent to an unregistered route.
If a route receives an unallowed request method, a "405 Method Not Allowed"
(:exc:`~werkzeug.exceptions.MethodNotAllowed`) will be raised. These are all
subclasses of :class:`~werkzeug.exceptions.HTTPException` and are provided by
default in Flask.
Flask gives you the ability to raise any HTTP exception registered by
Werkzeug. However, the default HTTP exceptions return simple exception
pages. You might want to show custom error pages to the user when an error occurs.
This can be done by registering error handlers.
When Flask catches an exception while handling a request, it is first looked up by code.
If no handler is registered for the code, Flask looks up the error by its class hierarchy; the most specific handler is chosen.
If no handler is registered, :class:`~werkzeug.exceptions.HTTPException` subclasses show a
generic message about their code, while other exceptions are converted to a
generic "500 Internal Server Error".
For example, if an instance of :exc:`ConnectionRefusedError` is raised,
and a handler is registered for :exc:`ConnectionError` and
:exc:`ConnectionRefusedError`, the more specific :exc:`ConnectionRefusedError`
handler is called with the exception instance to generate the response.
Handlers registered on the blueprint take precedence over those registered
globally on the application, assuming a blueprint is handling the request that
raises the exception. However, the blueprint cannot handle 404 routing errors
because the 404 occurs at the routing level before the blueprint can be
determined.
Generic Exception Handlers
``````````````````````````
It is possible to register error handlers for very generic base classes
such as ``HTTPException`` or even ``Exception``. However, be aware that
these will catch more than you might expect.
For example, an error handler for ``HTTPException`` might be useful for turning
the default HTML errors pages into JSON. However, this
handler will trigger for things you don't cause directly, such as 404
and 405 errors during routing. Be sure to craft your handler carefully
so you don't lose information about the HTTP error.
.. code-block:: python
from flask import json
from werkzeug.exceptions import HTTPException
@app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json"
return response
An error handler for ``Exception`` might seem useful for changing how
all errors, even unhandled ones, are presented to the user. However,
this is similar to doing ``except Exception:`` in Python, it will
capture *all* otherwise unhandled errors, including all HTTP status
codes.
In most cases it will be safer to register handlers for more
specific exceptions. Since ``HTTPException`` instances are valid WSGI
responses, you could also pass them through directly.
.. code-block:: python
from werkzeug.exceptions import HTTPException
@app.errorhandler(Exception)
def handle_exception(e):
# pass through HTTP errors
if isinstance(e, HTTPException):
return e
# now you're handling non-HTTP exceptions only
return render_template("500_generic.html", e=e), 500
Error handlers still respect the exception class hierarchy. If you
register handlers for both ``HTTPException`` and ``Exception``, the
``Exception`` handler will not handle ``HTTPException`` subclasses
because the ``HTTPException`` handler is more specific.
Unhandled Exceptions
````````````````````
When there is no error handler registered for an exception, a 500
Internal Server Error will be returned instead. See
:meth:`flask.Flask.handle_exception` for information about this
behavior.
If there is an error handler registered for ``InternalServerError``,
this will be invoked. As of Flask 1.1.0, this error handler will always
be passed an instance of ``InternalServerError``, not the original
unhandled error.
The original error is available as ``e.original_exception``.
An error handler for "500 Internal Server Error" will be passed uncaught
exceptions in addition to explicit 500 errors. In debug mode, a handler
for "500 Internal Server Error" will not be used. Instead, the
interactive debugger will be shown.
Custom Error Pages
------------------
Sometimes when building a Flask application, you might want to raise a
:exc:`~werkzeug.exceptions.HTTPException` to signal to the user that
something is wrong with the request. Fortunately, Flask comes with a handy
:func:`~flask.abort` function that aborts a request with a HTTP error from
werkzeug as desired. It will also provide a plain black and white error page
for you with a basic description, but nothing fancy.
Depending on the error code it is less or more likely for the user to
actually see such an error.
Consider the code below, we might have a user profile route, and if the user
fails to pass a username we can raise a "400 Bad Request". If the user passes a
username and we can't find it, we raise a "404 Not Found".
.. code-block:: python
from flask import abort, render_template, request
# a username needs to be supplied in the query args
# a successful request would be like /profile?username=jack
@app.route("/profile")
def user_profile():
username = request.arg.get("username")
# if a username isn't supplied in the request, return a 400 bad request
if username is None:
abort(400)
user = get_user(username=username)
# if a user can't be found by their username, return 404 not found
if user is None:
abort(404)
return render_template("profile.html", user=user)
Here is another example implementation for a "404 Page Not Found" exception:
.. code-block:: python
from flask import render_template
@app.errorhandler(404)
def page_not_found(e):
# note that we set the 404 status explicitly
return render_template('404.html'), 404
When using :doc:`/patterns/appfactories`:
.. code-block:: python
from flask import Flask, render_template
def page_not_found(e):
return render_template('404.html'), 404
def create_app(config_filename):
app = Flask(__name__)
app.register_error_handler(404, page_not_found)
return app
An example template might be this:
.. code-block:: html+jinja
{% extends "layout.html" %}
{% block title %}Page Not Found{% endblock %}
{% block body %}
<h1>Page Not Found</h1>
<p>What you were looking for is just not there.
<p><a href="{{ url_for('index') }}">go somewhere nice</a>
{% endblock %}
Further Examples
````````````````
The above examples wouldn't actually be an improvement on the default
exception pages. We can create a custom 500.html template like this:
.. code-block:: html+jinja
{% extends "layout.html" %}
{% block title %}Internal Server Error{% endblock %}
{% block body %}
<h1>Internal Server Error</h1>
<p>Oops... we seem to have made a mistake, sorry!</p>
<p><a href="{{ url_for('index') }}">Go somewhere nice instead</a>
{% endblock %}
It can be implemented by rendering the template on "500 Internal Server Error":
.. code-block:: python
from flask import render_template
@app.errorhandler(500)
def internal_server_error(e):
# note that we set the 500 status explicitly
return render_template('500.html'), 500
When using :doc:`/patterns/appfactories`:
.. code-block:: python
from flask import Flask, render_template
def internal_server_error(e):
return render_template('500.html'), 500
def create_app():
app = Flask(__name__)
app.register_error_handler(500, internal_server_error)
return app
When using :doc:`/blueprints`:
.. code-block:: python
from flask import Blueprint
blog = Blueprint('blog', __name__)
# as a decorator
@blog.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
# or with register_error_handler
blog.register_error_handler(500, internal_server_error)
Blueprint Error Handlers
------------------------
In :doc:`/blueprints`, most error handlers will work as expected.
However, there is a caveat concerning handlers for 404 and 405
exceptions. These error handlers are only invoked from an appropriate
``raise`` statement or a call to ``abort`` in another of the blueprint's
view functions; they are not invoked by, e.g., an invalid URL access.
This is because the blueprint does not "own" a certain URL space, so
the application instance has no way of knowing which blueprint error
handler it should run if given an invalid URL. If you would like to
execute different handling strategies for these errors based on URL
prefixes, they may be defined at the application level using the
``request`` proxy object.
.. code-block:: python
from flask import jsonify, render_template
# at the application level
# not the blueprint level
@app.errorhandler(404)
def page_not_found(e):
# if a request is in our blog URL space
if request.path.startswith('/blog/'):
# we return a custom blog 404 page
return render_template("blog/404.html"), 404
else:
# otherwise we return our generic site-wide 404 page
return render_template("404.html"), 404
@app.errorhandler(405)
def method_not_allowed(e):
# if a request has the wrong method to our API
if request.path.startswith('/api/'):
# we return a json saying so
return jsonify(message="Method Not Allowed"), 405
else:
# otherwise we return a generic site-wide 405 page
return render_template("405.html"), 405
Returning API Errors as JSON
----------------------------
When building APIs in Flask, some developers realise that the built-in
exceptions are not expressive enough for APIs and that the content type of
:mimetype:`text/html` they are emitting is not very useful for API consumers.
Using the same techniques as above and :func:`~flask.json.jsonify` we can return JSON
responses to API errors. :func:`~flask.abort` is called
with a ``description`` parameter. The error handler will
use that as the JSON error message, and set the status code to 404.
.. code-block:: python
from flask import abort, jsonify
@app.errorhandler(404)
def resource_not_found(e):
return jsonify(error=str(e)), 404
@app.route("/cheese")
def get_one_cheese():
resource = get_resource()
if resource is None:
abort(404, description="Resource not found")
return jsonify(resource)
We can also create custom exception classes. For instance, we can
introduce a new custom exception for an API that can take a proper human readable message,
a status code for the error and some optional payload to give more context
for the error.
This is a simple example:
.. code-block:: python
from flask import jsonify, request
class InvalidAPIUsage(Exception):
status_code = 400
def __init__(self, message, status_code=None, payload=None):
super().__init__()
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
def to_dict(self):
rv = dict(self.payload or ())
rv['message'] = self.message
return rv
@app.errorhandler(InvalidAPIUsage)
def invalid_api_usage(e):
return jsonify(e.to_dict()), e.status_code
# an API app route for getting user information
# a correct request might be /api/user?user_id=420
@app.route("/api/user")
def user_api(user_id):
user_id = request.arg.get("user_id")
if not user_id:
raise InvalidAPIUsage("No user id provided!")
user = get_user(user_id=user_id)
if not user:
raise InvalidAPIUsage("No such user!", status_code=404)
return jsonify(user.to_dict())
A view can now raise that exception with an error message. Additionally
some extra payload can be provided as a dictionary through the `payload`
parameter.
Logging
-------
See :doc:`/logging` for information about how to log exceptions, such as
by emailing them to admins.
Debugging
---------
See :doc:`/debugging` for information about how to debug errors in
development and production.

@ -0,0 +1,305 @@
Flask Extension Development
===========================
.. currentmodule:: flask
Extensions are extra packages that add functionality to a Flask
application. While `PyPI`_ contains many Flask extensions, you may not
find one that fits your need. If this is the case, you can create your
own, and publish it for others to use as well.
This guide will show how to create a Flask extension, and some of the
common patterns and requirements involved. Since extensions can do
anything, this guide won't be able to cover every possibility.
The best ways to learn about extensions are to look at how other
extensions you use are written, and discuss with others. Discuss your
design ideas with others on our `Discord Chat`_ or
`GitHub Discussions`_.
The best extensions share common patterns, so that anyone familiar with
using one extension won't feel completely lost with another. This can
only work if collaboration happens early.
Naming
------
A Flask extension typically has ``flask`` in its name as a prefix or
suffix. If it wraps another library, it should include the library name
as well. This makes it easy to search for extensions, and makes their
purpose clearer.
A general Python packaging recommendation is that the install name from
the package index and the name used in ``import`` statements should be
related. The import name is lowercase, with words separated by
underscores (``_``). The install name is either lower case or title
case, with words separated by dashes (``-``). If it wraps another
library, prefer using the same case as that library's name.
Here are some example install and import names:
- ``Flask-Name`` imported as ``flask_name``
- ``flask-name-lower`` imported as ``flask_name_lower``
- ``Flask-ComboName`` imported as ``flask_comboname``
- ``Name-Flask`` imported as ``name_flask``
The Extension Class and Initialization
--------------------------------------
All extensions will need some entry point that initializes the
extension with the application. The most common pattern is to create a
class that represents the extension's configuration and behavior, with
an ``init_app`` method to apply the extension instance to the given
application instance.
.. code-block:: python
class HelloExtension:
def __init__(self, app=None):
if app is not None:
self.init_app(app)
def init_app(self, app):
app.before_request(...)
It is important that the app is not stored on the extension, don't do
``self.app = app``. The only time the extension should have direct
access to an app is during ``init_app``, otherwise it should use
:data:`.current_app`.
This allows the extension to support the application factory pattern,
avoids circular import issues when importing the extension instance
elsewhere in a user's code, and makes testing with different
configurations easier.
.. code-block:: python
hello = HelloExtension()
def create_app():
app = Flask(__name__)
hello.init_app(app)
return app
Above, the ``hello`` extension instance exists independently of the
application. This means that other modules in a user's project can do
``from project import hello`` and use the extension in blueprints before
the app exists.
The :attr:`Flask.extensions` dict can be used to store a reference to
the extension on the application, or some other state specific to the
application. Be aware that this is a single namespace, so use a name
unique to your extension, such as the extension's name without the
"flask" prefix.
Adding Behavior
---------------
There are many ways that an extension can add behavior. Any setup
methods that are available on the :class:`Flask` object can be used
during an extension's ``init_app`` method.
A common pattern is to use :meth:`~Flask.before_request` to initialize
some data or a connection at the beginning of each request, then
:meth:`~Flask.teardown_request` to clean it up at the end. This can be
stored on :data:`.g`, discussed more below.
A more lazy approach is to provide a method that initializes and caches
the data or connection. For example, a ``ext.get_db`` method could
create a database connection the first time it's called, so that a view
that doesn't use the database doesn't create a connection.
Besides doing something before and after every view, your extension
might want to add some specific views as well. In this case, you could
define a :class:`Blueprint`, then call :meth:`~Flask.register_blueprint`
during ``init_app`` to add the blueprint to the app.
Configuration Techniques
------------------------
There can be multiple levels and sources of configuration for an
extension. You should consider what parts of your extension fall into
each one.
- Configuration per application instance, through ``app.config``
values. This is configuration that could reasonably change for each
deployment of an application. A common example is a URL to an
external resource, such as a database. Configuration keys should
start with the extension's name so that they don't interfere with
other extensions.
- Configuration per extension instance, through ``__init__``
arguments. This configuration usually affects how the extension
is used, such that it wouldn't make sense to change it per
deployment.
- Configuration per extension instance, through instance attributes
and decorator methods. It might be more ergonomic to assign to
``ext.value``, or use a ``@ext.register`` decorator to register a
function, after the extension instance has been created.
- Global configuration through class attributes. Changing a class
attribute like ``Ext.connection_class`` can customize default
behavior without making a subclass. This could be combined
per-extension configuration to override defaults.
- Subclassing and overriding methods and attributes. Making the API of
the extension itself something that can be overridden provides a
very powerful tool for advanced customization.
The :class:`~flask.Flask` object itself uses all of these techniques.
It's up to you to decide what configuration is appropriate for your
extension, based on what you need and what you want to support.
Configuration should not be changed after the application setup phase is
complete and the server begins handling requests. Configuration is
global, any changes to it are not guaranteed to be visible to other
workers.
Data During a Request
---------------------
When writing a Flask application, the :data:`~flask.g` object is used to
store information during a request. For example the
:doc:`tutorial <tutorial/database>` stores a connection to a SQLite
database as ``g.db``. Extensions can also use this, with some care.
Since ``g`` is a single global namespace, extensions must use unique
names that won't collide with user data. For example, use the extension
name as a prefix, or as a namespace.
.. code-block:: python
# an internal prefix with the extension name
g._hello_user_id = 2
# or an internal prefix as a namespace
from types import SimpleNamespace
g._hello = SimpleNamespace()
g._hello.user_id = 2
The data in ``g`` lasts for an application context. An application context is
active during a request, CLI command, or ``with app.app_context()`` block. If
you're storing something that should be closed, use
:meth:`~flask.Flask.teardown_appcontext` to ensure that it gets closed when the
app context ends. If it should only be valid during a request, or would not be
used in the CLI outside a request, use :meth:`~flask.Flask.teardown_request`.
Views and Models
----------------
Your extension views might want to interact with specific models in your
database, or some other extension or data connected to your application.
For example, let's consider a ``Flask-SimpleBlog`` extension that works
with Flask-SQLAlchemy to provide a ``Post`` model and views to write
and read posts.
The ``Post`` model needs to subclass the Flask-SQLAlchemy ``db.Model``
object, but that's only available once you've created an instance of
that extension, not when your extension is defining its views. So how
can the view code, defined before the model exists, access the model?
One method could be to use :doc:`views`. During ``__init__``, create
the model, then create the views by passing the model to the view
class's :meth:`~views.View.as_view` method.
.. code-block:: python
class PostAPI(MethodView):
def __init__(self, model):
self.model = model
def get(self, id):
post = self.model.query.get(id)
return jsonify(post.to_json())
class BlogExtension:
def __init__(self, db):
class Post(db.Model):
id = db.Column(primary_key=True)
title = db.Column(db.String, nullable=False)
self.post_model = Post
def init_app(self, app):
api_view = PostAPI.as_view(model=self.post_model)
db = SQLAlchemy()
blog = BlogExtension(db)
db.init_app(app)
blog.init_app(app)
Another technique could be to use an attribute on the extension, such as
``self.post_model`` from above. Add the extension to ``app.extensions``
in ``init_app``, then access
``current_app.extensions["simple_blog"].post_model`` from views.
You may also want to provide base classes so that users can provide
their own ``Post`` model that conforms to the API your extension
expects. So they could implement ``class Post(blog.BasePost)``, then
set it as ``blog.post_model``.
As you can see, this can get a bit complex. Unfortunately, there's no
perfect solution here, only different strategies and tradeoffs depending
on your needs and how much customization you want to offer. Luckily,
this sort of resource dependency is not a common need for most
extensions. Remember, if you need help with design, ask on our
`Discord Chat`_ or `GitHub Discussions`_.
Recommended Extension Guidelines
--------------------------------
Flask previously had the concept of "approved extensions", where the
Flask maintainers evaluated the quality, support, and compatibility of
the extensions before listing them. While the list became too difficult
to maintain over time, the guidelines are still relevant to all
extensions maintained and developed today, as they help the Flask
ecosystem remain consistent and compatible.
1. An extension requires a maintainer. In the event an extension author
would like to move beyond the project, the project should find a new
maintainer and transfer access to the repository, documentation,
PyPI, and any other services. The `Pallets-Eco`_ organization on
GitHub allows for community maintenance with oversight from the
Pallets maintainers.
2. The naming scheme is *Flask-ExtensionName* or *ExtensionName-Flask*.
It must provide exactly one package or module named
``flask_extension_name``.
3. The extension must use an open source license. The Python web
ecosystem tends to prefer BSD or MIT. It must be open source and
publicly available.
4. The extension's API must have the following characteristics:
- It must support multiple applications running in the same Python
process. Use ``current_app`` instead of ``self.app``, store
configuration and state per application instance.
- It must be possible to use the factory pattern for creating
applications. Use the ``ext.init_app()`` pattern.
5. From a clone of the repository, an extension with its dependencies
must be installable in editable mode with ``pip install -e .``.
6. It must ship tests that can be invoked with a common tool like
``tox -e py``, ``nox -s test`` or ``pytest``. If not using ``tox``,
the test dependencies should be specified in a requirements file.
The tests must be part of the sdist distribution.
7. A link to the documentation or project website must be in the PyPI
metadata or the readme. The documentation should use the Flask theme
from the `Official Pallets Themes`_.
8. The extension's dependencies should not use upper bounds or assume
any particular version scheme, but should use lower bounds to
indicate minimum compatibility support. For example,
``sqlalchemy>=1.4``.
9. Indicate the versions of Python supported using ``python_requires=">=version"``.
Flask and Pallets policy is to support all Python versions that are not
within six months of end of life (EOL). See Python's `EOL calendar`_ for
timing.
.. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask
.. _Discord Chat: https://discord.gg/pallets
.. _GitHub Discussions: https://github.com/pallets/flask/discussions
.. _Official Pallets Themes: https://pypi.org/project/Pallets-Sphinx-Themes/
.. _Pallets-Eco: https://github.com/pallets-eco
.. _EOL calendar: https://devguide.python.org/versions/

@ -0,0 +1,48 @@
Extensions
==========
Extensions are extra packages that add functionality to a Flask
application. For example, an extension might add support for sending
email or connecting to a database. Some extensions add entire new
frameworks to help build certain types of applications, like a REST API.
Finding Extensions
------------------
Flask extensions are usually named "Flask-Foo" or "Foo-Flask". You can
search PyPI for packages tagged with `Framework :: Flask <pypi_>`_.
Using Extensions
----------------
Consult each extension's documentation for installation, configuration,
and usage instructions. Generally, extensions pull their own
configuration from :attr:`app.config <flask.Flask.config>` and are
passed an application instance during initialization. For example,
an extension called "Flask-Foo" might be used like this::
from flask_foo import Foo
foo = Foo()
app = Flask(__name__)
app.config.update(
FOO_BAR='baz',
FOO_SPAM='eggs',
)
foo.init_app(app)
Building Extensions
-------------------
While `PyPI <pypi_>`_ contains many Flask extensions, you may not find
an extension that fits your need. If this is the case, you can create
your own, and publish it for others to use as well. Read
:doc:`extensiondev` to develop your own Flask extension.
.. _pypi: https://pypi.org/search/?c=Framework+%3A%3A+Flask

@ -0,0 +1,88 @@
.. rst-class:: hide-header
Welcome to Flask
================
.. image:: _static/flask-name.svg
:align: center
:height: 200px
Welcome to Flask's documentation. Flask is a lightweight WSGI web application framework.
It is designed to make getting started quick and easy, with the ability to scale up to
complex applications.
Get started with :doc:`installation`
and then get an overview with the :doc:`quickstart`. There is also a
more detailed :doc:`tutorial/index` that shows how to create a small but
complete application with Flask. Common patterns are described in the
:doc:`patterns/index` section. The rest of the docs describe each
component of Flask in detail, with a full reference in the :doc:`api`
section.
Flask depends on the `Werkzeug`_ WSGI toolkit, the `Jinja`_ template engine, and the
`Click`_ CLI toolkit. Be sure to check their documentation as well as Flask's when
looking for information.
.. _Werkzeug: https://werkzeug.palletsprojects.com
.. _Jinja: https://jinja.palletsprojects.com
.. _Click: https://click.palletsprojects.com
User's Guide
------------
Flask provides configuration and conventions, with sensible defaults, to get started.
This section of the documentation explains the different parts of the Flask framework
and how they can be used, customized, and extended. Beyond Flask itself, look for
community-maintained extensions to add even more functionality.
.. toctree::
:maxdepth: 2
installation
quickstart
tutorial/index
templating
testing
errorhandling
debugging
logging
config
signals
views
lifecycle
appcontext
blueprints
extensions
cli
server
shell
patterns/index
web-security
deploying/index
async-await
API Reference
-------------
If you are looking for information on a specific function, class or
method, this part of the documentation is for you.
.. toctree::
:maxdepth: 2
api
Additional Notes
----------------
.. toctree::
:maxdepth: 2
design
extensiondev
contributing
license
changes

@ -0,0 +1,144 @@
Installation
============
Python Version
--------------
We recommend using the latest version of Python. Flask supports Python 3.10 and newer.
Dependencies
------------
These distributions will be installed automatically when installing Flask.
* `Werkzeug`_ implements WSGI, the standard Python interface between
applications and servers.
* `Jinja`_ is a template language that renders the pages your application
serves.
* `MarkupSafe`_ comes with Jinja. It escapes untrusted input when rendering
templates to avoid injection attacks.
* `ItsDangerous`_ securely signs data to ensure its integrity. This is used
to protect Flask's session cookie.
* `Click`_ is a framework for writing command line applications. It provides
the ``flask`` command and allows adding custom management commands.
* `Blinker`_ provides support for :doc:`signals`.
.. _Werkzeug: https://palletsprojects.com/p/werkzeug/
.. _Jinja: https://palletsprojects.com/p/jinja/
.. _MarkupSafe: https://palletsprojects.com/p/markupsafe/
.. _ItsDangerous: https://palletsprojects.com/p/itsdangerous/
.. _Click: https://palletsprojects.com/p/click/
.. _Blinker: https://blinker.readthedocs.io/
Optional dependencies
~~~~~~~~~~~~~~~~~~~~~
These distributions will not be installed automatically. Flask will detect and
use them if you install them.
* `python-dotenv`_ enables support for :ref:`dotenv` when running ``flask``
commands.
* `Watchdog`_ provides a faster, more efficient reloader for the development
server.
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
.. _watchdog: https://pythonhosted.org/watchdog/
greenlet
~~~~~~~~
You may choose to use gevent or eventlet with your application. In this
case, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
These are not minimum supported versions, they only indicate the first
versions that added necessary features. You should use the latest
versions of each.
Virtual environments
--------------------
Use a virtual environment to manage the dependencies for your project, both in
development and in production.
What problem does a virtual environment solve? The more Python projects you
have, the more likely it is that you need to work with different versions of
Python libraries, or even Python itself. Newer versions of libraries for one
project can break compatibility in another project.
Virtual environments are independent groups of Python libraries, one for each
project. Packages installed for one project will not affect other projects or
the operating system's packages.
Python comes bundled with the :mod:`venv` module to create virtual
environments.
.. _install-create-env:
Create an environment
~~~~~~~~~~~~~~~~~~~~~
Create a project folder and a :file:`.venv` folder within:
.. tabs::
.. group-tab:: macOS/Linux
.. code-block:: text
$ mkdir myproject
$ cd myproject
$ python3 -m venv .venv
.. group-tab:: Windows
.. code-block:: text
> mkdir myproject
> cd myproject
> py -3 -m venv .venv
.. _install-activate-env:
Activate the environment
~~~~~~~~~~~~~~~~~~~~~~~~
Before you work on your project, activate the corresponding environment:
.. tabs::
.. group-tab:: macOS/Linux
.. code-block:: text
$ . .venv/bin/activate
.. group-tab:: Windows
.. code-block:: text
> .venv\Scripts\activate
Your shell prompt will change to show the name of the activated
environment.
Install Flask
-------------
Within the activated environment, use the following command to install
Flask:
.. code-block:: sh
$ pip install Flask
Flask is now installed. Check out the :doc:`/quickstart` or go to the
:doc:`Documentation Overview </index>`.

@ -0,0 +1,5 @@
BSD-3-Clause License
====================
.. literalinclude:: ../LICENSE.txt
:language: text

@ -0,0 +1,171 @@
Application Structure and Lifecycle
===================================
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.
Application Setup
-----------------
The first step in creating a Flask application is creating the application object. Each
Flask application is an instance of the :class:`.Flask` class, which collects all
configuration, extensions, and views.
.. code-block:: python
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:
- Adding routes, view functions, and other request handlers with ``@app.route``,
``@app.errorhandler``, ``@app.before_request``, etc.
- Registering blueprints.
- Loading configuration with ``app.config``.
- Setting up the Jinja template environment with ``app.jinja_env``.
- Setting a session interface, instead of the default itsdangerous cookie.
- Setting a JSON provider with ``app.json``, instead of the default provider.
- Creating and initializing Flask extensions.
Serving the Application
-----------------------
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 :doc:`deploying/index`.
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.
#. Browser or other client makes HTTP request.
#. WSGI server receives request.
#. WSGI server converts HTTP data to WSGI ``environ`` dict.
#. WSGI server calls WSGI application with the ``environ``.
#. Flask, the WSGI application, does all its internal processing to route the request
to a view function, handle errors, etc.
#. Flask translates View function return into WSGI response data, passes it to WSGI
server.
#. WSGI server creates and send an HTTP response.
#. Client receives the HTTP response.
Middleware
~~~~~~~~~~
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
:class:`~werkzeug.middleware.proxy_fix.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.
How a Request is Handled
------------------------
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.
#. WSGI server calls the Flask object, which calls :meth:`.Flask.wsgi_app`.
#. An :class:`.AppContext` object is created. This converts the WSGI ``environ``
dict into a :class:`.Request` object.
#. The :doc:`app context <appcontext>` is pushed, which makes
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session`
available.
#. The :data:`.appcontext_pushed` signal is sent.
#. The URL is matched against the URL rules registered with the :meth:`~.Flask.route`
decorator during application setup. If there is no match, the error - usually a 404,
405, or redirect - is stored to be handled later.
#. The :data:`.request_started` signal is sent.
#. Any :meth:`~.Flask.url_value_preprocessor` decorated functions are called.
#. Any :meth:`~.Flask.before_request` decorated functions are called. If any of
these function returns a value it is treated as the response immediately.
#. If the URL didn't match a route a few steps ago, that error is raised now.
#. The :meth:`~.Flask.route` decorated view function associated with the matched URL
is called and returns a value to be used as the response.
#. If any step so far raised an exception, and there is an :meth:`~.Flask.errorhandler`
decorated function that matches the exception class or HTTP error code, it is
called to handle the error and return a response.
#. Whatever returned a response value - a before request function, the view, or an
error handler, that value is converted to a :class:`.Response` object.
#. Any :func:`~.after_this_request` decorated functions are called, which can modify
the response object. They are then cleared.
#. Any :meth:`~.Flask.after_request` decorated functions are called, which can modify
the response object.
#. The session is saved, persisting any modified session data using the app's
:attr:`~.Flask.session_interface`.
#. The :data:`.request_finished` signal is sent.
#. If any step so far raised an exception, and it was not handled by an error handler
function, it is handled now. HTTP exceptions are treated as responses with their
corresponding status code, other exceptions are converted to a generic 500 response.
The :data:`.got_request_exception` signal is sent.
#. The response object's status, headers, and body are returned to the WSGI server.
#. Any :meth:`~.Flask.teardown_request` decorated functions are called.
#. The :data:`.request_tearing_down` signal is sent.
#. Any :meth:`~.Flask.teardown_appcontext` decorated functions are called.
#. The :data:`.appcontext_tearing_down` signal is sent.
#. The app context is popped, :data:`.current_app`, :data:`.g`, :data:`.request`,
and :data:`.session` are no longer available.
#. The :data:`.appcontext_popped` signal is sent.
When executing a CLI command or plain app context without request data, the same
order of steps is followed, omitting the steps that refer to the request.
A :class:`Blueprint` can add handlers for these events that are specific to the
blueprint. The handlers for a blueprint will run if the blueprint
owns the route that matches the request.
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 :doc:`api` to explore further.

@ -0,0 +1,183 @@
Logging
=======
Flask uses standard Python :mod:`logging`. Messages about your Flask
application are logged with :meth:`app.logger <flask.Flask.logger>`,
which takes the same name as :attr:`app.name <flask.Flask.name>`. This
logger can also be used to log your own messages.
.. code-block:: python
@app.route('/login', methods=['POST'])
def login():
user = get_user(request.form['username'])
if user.check_password(request.form['password']):
login_user(user)
app.logger.info('%s logged in successfully', user.username)
return redirect(url_for('index'))
else:
app.logger.info('%s failed to log in', user.username)
abort(401)
If you don't configure logging, Python's default log level is usually
'warning'. Nothing below the configured level will be visible.
Basic Configuration
-------------------
When you want to configure logging for your project, you should do it as soon
as possible when the program starts. If :meth:`app.logger <flask.Flask.logger>`
is accessed before logging is configured, it will add a default handler. If
possible, configure logging before creating the application object.
This example uses :func:`~logging.config.dictConfig` to create a logging
configuration similar to Flask's default, except for all logs::
from logging.config import dictConfig
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
}},
'root': {
'level': 'INFO',
'handlers': ['wsgi']
}
})
app = Flask(__name__)
Default Configuration
`````````````````````
If you do not configure logging yourself, Flask will add a
:class:`~logging.StreamHandler` to :meth:`app.logger <flask.Flask.logger>`
automatically. During requests, it will write to the stream specified by the
WSGI server in ``environ['wsgi.errors']`` (which is usually
:data:`sys.stderr`). Outside a request, it will log to :data:`sys.stderr`.
Removing the Default Handler
````````````````````````````
If you configured logging after accessing
:meth:`app.logger <flask.Flask.logger>`, and need to remove the default
handler, you can import and remove it::
from flask.logging import default_handler
app.logger.removeHandler(default_handler)
Email Errors to Admins
----------------------
When running the application on a remote server for production, you probably
won't be looking at the log messages very often. The WSGI server will probably
send log messages to a file, and you'll only check that file if a user tells
you something went wrong.
To be proactive about discovering and fixing bugs, you can configure a
:class:`logging.handlers.SMTPHandler` to send an email when errors and higher
are logged. ::
import logging
from logging.handlers import SMTPHandler
mail_handler = SMTPHandler(
mailhost='127.0.0.1',
fromaddr='server-error@example.com',
toaddrs=['admin@example.com'],
subject='Application Error'
)
mail_handler.setLevel(logging.ERROR)
mail_handler.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
))
if not app.debug:
app.logger.addHandler(mail_handler)
This requires that you have an SMTP server set up on the same server. See the
Python docs for more information about configuring the handler.
Injecting Request Information
-----------------------------
Seeing more information about the request, such as the IP address, may help
debugging some errors. You can subclass :class:`logging.Formatter` to inject
your own fields that can be used in messages. You can change the formatter for
Flask's default handler, the mail handler defined above, or any other
handler. ::
from flask import has_request_context, request
from flask.logging import default_handler
class RequestFormatter(logging.Formatter):
def format(self, record):
if has_request_context():
record.url = request.url
record.remote_addr = request.remote_addr
else:
record.url = None
record.remote_addr = None
return super().format(record)
formatter = RequestFormatter(
'[%(asctime)s] %(remote_addr)s requested %(url)s\n'
'%(levelname)s in %(module)s: %(message)s'
)
default_handler.setFormatter(formatter)
mail_handler.setFormatter(formatter)
Other Libraries
---------------
Other libraries may use logging extensively, and you want to see relevant
messages from those logs too. The simplest way to do this is to add handlers
to the root logger instead of only the app logger. ::
from flask.logging import default_handler
root = logging.getLogger()
root.addHandler(default_handler)
root.addHandler(mail_handler)
Depending on your project, it may be more useful to configure each logger you
care about separately, instead of configuring only the root logger. ::
for logger in (
logging.getLogger(app.name),
logging.getLogger('sqlalchemy'),
logging.getLogger('other_package'),
):
logger.addHandler(default_handler)
logger.addHandler(mail_handler)
Werkzeug
````````
Werkzeug logs basic request/response information to the ``'werkzeug'`` logger.
If the root logger has no handlers configured, Werkzeug adds a
:class:`~logging.StreamHandler` to its logger.
Flask Extensions
````````````````
Depending on the situation, an extension may choose to log to
:meth:`app.logger <flask.Flask.logger>` or its own named logger. Consult each
extension's documentation for details.

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

@ -0,0 +1,189 @@
Application Dispatching
=======================
Application dispatching is the process of combining multiple Flask
applications on the WSGI level. You can combine not only Flask
applications but any WSGI application. This would allow you to run a
Django and a Flask application in the same interpreter side by side if
you want. The usefulness of this depends on how the applications work
internally.
The fundamental difference from :doc:`packages` is that in this case you
are running the same or different Flask applications that are entirely
isolated from each other. They run different configurations and are
dispatched on the WSGI level.
Working with this Document
--------------------------
Each of the techniques and examples below results in an ``application``
object that can be run with any WSGI server. For development, use the
``flask run`` command to start a development server. For production, see
:doc:`/deploying/index`.
.. code-block:: python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
Combining Applications
----------------------
If you have entirely separated applications and you want them to work next
to each other in the same Python interpreter process you can take
advantage of the :class:`werkzeug.wsgi.DispatcherMiddleware`. The idea
here is that each Flask application is a valid WSGI application and they
are combined by the dispatcher middleware into a larger one that is
dispatched based on prefix.
For example you could have your main application run on ``/`` and your
backend interface on ``/backend``.
.. code-block:: python
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend
application = DispatcherMiddleware(frontend, {
'/backend': backend
})
Dispatch by Subdomain
---------------------
Sometimes you might want to use multiple instances of the same application
with different configurations. Assuming the application is created inside
a function and you can call that function to instantiate it, that is
really easy to implement. In order to develop your application to support
creating new instances in functions have a look at the
:doc:`appfactories` pattern.
A very common example would be creating applications per subdomain. For
instance you configure your webserver to dispatch all requests for all
subdomains to your application and you then use the subdomain information
to create user-specific instances. Once you have your server set up to
listen on all subdomains you can use a very simple WSGI application to do
the dynamic application creation.
The perfect level for abstraction in that regard is the WSGI layer. You
write your own WSGI application that looks at the request that comes and
delegates it to your Flask application. If that application does not
exist yet, it is dynamically created and remembered.
.. code-block:: python
from threading import Lock
class SubdomainDispatcher:
def __init__(self, domain, create_app):
self.domain = domain
self.create_app = create_app
self.lock = Lock()
self.instances = {}
def get_application(self, host):
host = host.split(':')[0]
assert host.endswith(self.domain), 'Configuration error'
subdomain = host[:-len(self.domain)].rstrip('.')
with self.lock:
app = self.instances.get(subdomain)
if app is None:
app = self.create_app(subdomain)
self.instances[subdomain] = app
return app
def __call__(self, environ, start_response):
app = self.get_application(environ['HTTP_HOST'])
return app(environ, start_response)
This dispatcher can then be used like this:
.. code-block:: python
from myapplication import create_app, get_user_for_subdomain
from werkzeug.exceptions import NotFound
def make_app(subdomain):
user = get_user_for_subdomain(subdomain)
if user is None:
# if there is no user for that subdomain we still have
# to return a WSGI application that handles that request.
# We can then just return the NotFound() exception as
# application which will render a default 404 page.
# You might also redirect the user to the main page then
return NotFound()
# otherwise create the application for the specific user
return create_app(user)
application = SubdomainDispatcher('example.com', make_app)
Dispatch by Path
----------------
Dispatching by a path on the URL is very similar. Instead of looking at
the ``Host`` header to figure out the subdomain one simply looks at the
request path up to the first slash.
.. code-block:: python
from threading import Lock
from wsgiref.util import shift_path_info
class PathDispatcher:
def __init__(self, default_app, create_app):
self.default_app = default_app
self.create_app = create_app
self.lock = Lock()
self.instances = {}
def get_application(self, prefix):
with self.lock:
app = self.instances.get(prefix)
if app is None:
app = self.create_app(prefix)
if app is not None:
self.instances[prefix] = app
return app
def __call__(self, environ, start_response):
app = self.get_application(_peek_path_info(environ))
if app is not None:
shift_path_info(environ)
else:
app = self.default_app
return app(environ, start_response)
def _peek_path_info(environ):
segments = environ.get("PATH_INFO", "").lstrip("/").split("/", 1)
if segments:
return segments[0]
return None
The big difference between this and the subdomain one is that this one
falls back to another application if the creator function returns ``None``.
.. code-block:: python
from myapplication import create_app, default_app, get_user_for_prefix
def make_app(prefix):
user = get_user_for_prefix(prefix)
if user is not None:
return create_app(user)
application = PathDispatcher(default_app, make_app)

@ -0,0 +1,118 @@
Application Factories
=====================
If you are already using packages and blueprints for your application
(:doc:`/blueprints`) there are a couple of really nice ways to further improve
the experience. A common pattern is creating the application object when
the blueprint is imported. But if you move the creation of this object
into a function, you can then create multiple instances of this app later.
So why would you want to do this?
1. Testing. You can have instances of the application with different
settings to test every case.
2. Multiple instances. Imagine you want to run different versions of the
same application. Of course you could have multiple instances with
different configs set up in your webserver, but if you use factories,
you can have multiple instances of the same application running in the
same application process which can be handy.
So how would you then actually implement that?
Basic Factories
---------------
The idea is to set up the application in a function. Like this::
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
The downside is that you cannot use the application object in the blueprints
at import time. You can however use it from within a request. How do you
get access to the application with the config? Use
:data:`~flask.current_app`::
from flask import current_app, Blueprint, render_template
admin = Blueprint('admin', __name__, url_prefix='/admin')
@admin.route('/')
def index():
return render_template(current_app.config['INDEX_TEMPLATE'])
Here we look up the name of a template in the config.
Factories & Extensions
----------------------
It's preferable to create your extensions and app factories so that the
extension object does not initially get bound to the application.
Using `Flask-SQLAlchemy <https://flask-sqlalchemy.palletsprojects.com/>`_,
as an example, you should not do something along those lines::
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
db = SQLAlchemy(app)
But, rather, in model.py (or equivalent)::
db = SQLAlchemy()
and in your application.py (or equivalent)::
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
Using this design pattern, no application-specific state is stored on the
extension object, so one extension object can be used for multiple apps.
For more information about the design of extensions refer to :doc:`/extensiondev`.
Using Applications
------------------
To run such an application, you can use the :command:`flask` command:
.. code-block:: text
$ flask --app hello run
Flask will automatically detect the factory if it is named
``create_app`` or ``make_app`` in ``hello``. You can also pass arguments
to the factory like this:
.. code-block:: text
$ flask --app 'hello:create_app(local_auth=True)' run
Then the ``create_app`` factory in ``hello`` is called with the keyword
argument ``local_auth=True``. See :doc:`/cli` for more detail.
Factory Improvements
--------------------
The factory function above is not very clever, but you can improve it.
The following changes are straightforward to implement:
1. Make it possible to pass in configuration values for unit tests so that
you don't have to create config files on the filesystem.
2. Call a function from a blueprint when the application is setting up so
that you have a place to modify attributes of the application (like
hooking in before/after request handlers etc.)
3. Add in WSGI middlewares when the application is being created if necessary.

@ -0,0 +1,16 @@
Caching
=======
When your application runs slow, throw some caches in. Well, at least
it's the easiest way to speed up things. What does a cache do? Say you
have a function that takes some time to complete but the results would
still be good enough if they were 5 minutes old. So then the idea is that
you actually put the result of that calculation into a cache for some
time.
Flask itself does not provide caching for you, but `Flask-Caching`_, an
extension for Flask does. Flask-Caching supports various backends, and it is
even possible to develop your own caching backend.
.. _Flask-Caching: https://flask-caching.readthedocs.io/en/latest/

@ -0,0 +1,242 @@
Background Tasks with Celery
============================
If your application has a long running task, such as processing some uploaded data or
sending email, you don't want to wait for it to finish during a request. Instead, use a
task queue to send the necessary data to another process that will run the task in the
background while the request returns immediately.
`Celery`_ is a powerful task queue that can be used for simple background tasks as well
as complex multi-stage programs and schedules. This guide will show you how to configure
Celery using Flask. Read Celery's `First Steps with Celery`_ guide to learn how to use
Celery itself.
.. _Celery: https://celery.readthedocs.io
.. _First Steps with Celery: https://celery.readthedocs.io/en/latest/getting-started/first-steps-with-celery.html
The Flask repository contains `an example <https://github.com/pallets/flask/tree/main/examples/celery>`_
based on the information on this page, which also shows how to use JavaScript to submit
tasks and poll for progress and results.
Install
-------
Install Celery from PyPI, for example using pip:
.. code-block:: text
$ pip install celery
Integrate Celery with Flask
---------------------------
You can use Celery without any integration with Flask, but it's convenient to configure
it through Flask's config, and to let tasks access the Flask application.
Celery uses similar ideas to Flask, with a ``Celery`` app object that has configuration
and registers tasks. While creating a Flask app, use the following code to create and
configure a Celery app as well.
.. code-block:: python
from celery import Celery, Task
def celery_init_app(app: Flask) -> Celery:
class FlaskTask(Task):
def __call__(self, *args: object, **kwargs: object) -> object:
with app.app_context():
return self.run(*args, **kwargs)
celery_app = Celery(app.name, task_cls=FlaskTask)
celery_app.config_from_object(app.config["CELERY"])
celery_app.set_default()
app.extensions["celery"] = celery_app
return celery_app
This creates and returns a ``Celery`` app object. Celery `configuration`_ is taken from
the ``CELERY`` key in the Flask configuration. The Celery app is set as the default, so
that it is seen during each request. The ``Task`` subclass automatically runs task
functions with a Flask app context active, so that services like your database
connections are available.
.. _configuration: https://celery.readthedocs.io/en/stable/userguide/configuration.html
Here's a basic ``example.py`` that configures Celery to use Redis for communication. We
enable a result backend, but ignore results by default. This allows us to store results
only for tasks where we care about the result.
.. code-block:: python
from flask import Flask
app = Flask(__name__)
app.config.from_mapping(
CELERY=dict(
broker_url="redis://localhost",
result_backend="redis://localhost",
task_ignore_result=True,
),
)
celery_app = celery_init_app(app)
Point the ``celery worker`` command at this and it will find the ``celery_app`` object.
.. code-block:: text
$ celery -A example worker --loglevel INFO
You can also run the ``celery beat`` command to run tasks on a schedule. See Celery's
docs for more information about defining schedules.
.. code-block:: text
$ celery -A example beat --loglevel INFO
Application Factory
-------------------
When using the Flask application factory pattern, call the ``celery_init_app`` function
inside the factory. It sets ``app.extensions["celery"]`` to the Celery app object, which
can be used to get the Celery app from the Flask app returned by the factory.
.. code-block:: python
def create_app() -> Flask:
app = Flask(__name__)
app.config.from_mapping(
CELERY=dict(
broker_url="redis://localhost",
result_backend="redis://localhost",
task_ignore_result=True,
),
)
app.config.from_prefixed_env()
celery_init_app(app)
return app
To use ``celery`` commands, Celery needs an app object, but that's no longer directly
available. Create a ``make_celery.py`` file that calls the Flask app factory and gets
the Celery app from the returned Flask app.
.. code-block:: python
from example import create_app
flask_app = create_app()
celery_app = flask_app.extensions["celery"]
Point the ``celery`` command to this file.
.. code-block:: text
$ celery -A make_celery worker --loglevel INFO
$ celery -A make_celery beat --loglevel INFO
Defining Tasks
--------------
Using ``@celery_app.task`` to decorate task functions requires access to the
``celery_app`` object, which won't be available when using the factory pattern. It also
means that the decorated tasks are tied to the specific Flask and Celery app instances,
which could be an issue during testing if you change configuration for a test.
Instead, use Celery's ``@shared_task`` decorator. This creates task objects that will
access whatever the "current app" is, which is a similar concept to Flask's blueprints
and app context. This is why we called ``celery_app.set_default()`` above.
Here's an example task that adds two numbers together and returns the result.
.. code-block:: python
from celery import shared_task
@shared_task(ignore_result=False)
def add_together(a: int, b: int) -> int:
return a + b
Earlier, we configured Celery to ignore task results by default. Since we want to know
the return value of this task, we set ``ignore_result=False``. On the other hand, a task
that didn't need a result, such as sending an email, wouldn't set this.
Calling Tasks
-------------
The decorated function becomes a task object with methods to call it in the background.
The simplest way is to use the ``delay(*args, **kwargs)`` method. See Celery's docs for
more methods.
A Celery worker must be running to run the task. Starting a worker is shown in the
previous sections.
.. code-block:: python
from flask import request
@app.post("/add")
def start_add() -> dict[str, object]:
a = request.form.get("a", type=int)
b = request.form.get("b", type=int)
result = add_together.delay(a, b)
return {"result_id": result.id}
The route doesn't get the task's result immediately. That would defeat the purpose by
blocking the response. Instead, we return the running task's result id, which we can use
later to get the result.
Getting Results
---------------
To fetch the result of the task we started above, we'll add another route that takes the
result id we returned before. We return whether the task is finished (ready), whether it
finished successfully, and what the return value (or error) was if it is finished.
.. code-block:: python
from celery.result import AsyncResult
@app.get("/result/<id>")
def task_result(id: str) -> dict[str, object]:
result = AsyncResult(id)
return {
"ready": result.ready(),
"successful": result.successful(),
"value": result.result if result.ready() else None,
}
Now you can start the task using the first route, then poll for the result using the
second route. This keeps the Flask request workers from being blocked waiting for tasks
to finish.
The Flask repository contains `an example <https://github.com/pallets/flask/tree/main/examples/celery>`_
using JavaScript to submit tasks and poll for progress and results.
Passing Data to Tasks
---------------------
The "add" task above took two integers as arguments. To pass arguments to tasks, Celery
has to serialize them to a format that it can pass to other processes. Therefore,
passing complex objects is not recommended. For example, it would be impossible to pass
a SQLAlchemy model object, since that object is probably not serializable and is tied to
the session that queried it.
Pass the minimal amount of data necessary to fetch or recreate any complex data within
the task. Consider a task that will run when the logged in user asks for an archive of
their data. The Flask request knows the logged in user, and has the user object queried
from the database. It got that by querying the database for a given id, so the task can
do the same thing. Pass the user's id rather than the user object.
.. code-block:: python
@shared_task
def generate_user_archive(user_id: str) -> None:
user = db.session.get(User, user_id)
...
generate_user_archive.delay(current_user.id)

@ -0,0 +1,44 @@
Deferred Request Callbacks
==========================
One of the design principles of Flask is that response objects are created and
passed down a chain of potential callbacks that can modify them or replace
them. When the request handling starts, there is no response object yet. It is
created as necessary either by a view function or by some other component in
the system.
What happens if you want to modify the response at a point where the response
does not exist yet? A common example for that would be a
:meth:`~flask.Flask.before_request` callback that wants to set a cookie on the
response object.
One way is to avoid the situation. Very often that is possible. For instance
you can try to move that logic into a :meth:`~flask.Flask.after_request`
callback instead. However, sometimes moving code there makes it
more complicated or awkward to reason about.
As an alternative, you can use :func:`~flask.after_this_request` to register
callbacks that will execute after only the current request. This way you can
defer code execution from anywhere in the application, based on the current
request.
At any time during a request, we can register a function to be called at the
end of the request. For example you can remember the current language of the
user in a cookie in a :meth:`~flask.Flask.before_request` callback::
from flask import request, after_this_request
@app.before_request
def detect_user_language():
language = request.cookies.get('user_lang')
if language is None:
language = guess_language_from_request()
# when the response exists, set a cookie with the language
@after_this_request
def remember_language(response):
response.set_cookie('user_lang', language)
return response
g.language = language

@ -0,0 +1,56 @@
Adding a favicon
================
A "favicon" is an icon used by browsers for tabs and bookmarks. This helps
to distinguish your website and to give it a unique brand.
A common question is how to add a favicon to a Flask application. First, of
course, you need an icon. It should be 16 × 16 pixels and in the ICO file
format. This is not a requirement but a de-facto standard supported by all
relevant browsers. Put the icon in your static directory as
:file:`favicon.ico`.
Now, to get browsers to find your icon, the correct way is to add a link
tag in your HTML. So, for example:
.. sourcecode:: html+jinja
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
That's all you need for most browsers, however some really old ones do not
support this standard. The old de-facto standard is to serve this file,
with this name, at the website root. If your application is not mounted at
the root path of the domain you either need to configure the web server to
serve the icon at the root or if you can't do that you're out of luck. If
however your application is the root you can simply route a redirect::
app.add_url_rule(
"/favicon.ico",
endpoint="favicon",
redirect_to=url_for("static", filename="favicon.ico"),
)
If you want to save the extra redirect request you can also write a view
using :func:`~flask.send_from_directory`::
import os
from flask import send_from_directory
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico', mimetype='image/vnd.microsoft.icon')
We can leave out the explicit mimetype and it will be guessed, but we may
as well specify it to avoid the extra guessing, as it will always be the
same.
The above will serve the icon via your application and if possible it's
better to configure your dedicated web server to serve it; refer to the
web server's documentation.
See also
--------
* The `Favicon <https://en.wikipedia.org/wiki/Favicon>`_ article on
Wikipedia

@ -0,0 +1,182 @@
Uploading Files
===============
Ah yes, the good old problem of file uploads. The basic idea of file
uploads is actually quite simple. It basically works like this:
1. A ``<form>`` tag is marked with ``enctype=multipart/form-data``
and an ``<input type=file>`` is placed in that form.
2. The application accesses the file from the :attr:`~flask.request.files`
dictionary on the request object.
3. use the :meth:`~werkzeug.datastructures.FileStorage.save` method of the file to save
the file permanently somewhere on the filesystem.
A Gentle Introduction
---------------------
Let's start with a very basic application that uploads a file to a
specific upload folder and displays a file to the user. Let's look at the
bootstrapping code for our application::
import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
So first we need a couple of imports. Most should be straightforward, the
:func:`werkzeug.secure_filename` is explained a little bit later. The
``UPLOAD_FOLDER`` is where we will store the uploaded files and the
``ALLOWED_EXTENSIONS`` is the set of allowed file extensions.
Why do we limit the extensions that are allowed? You probably don't want
your users to be able to upload everything there if the server is directly
sending out the data to the client. That way you can make sure that users
are not able to upload HTML files that would cause XSS problems (see
:ref:`security-xss`). Also make sure to disallow ``.php`` files if the server
executes them, but who has PHP installed on their server, right? :)
Next the functions that check if an extension is valid and that uploads
the file and redirects the user to the URL for the uploaded file::
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('download_file', name=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
'''
So what does that :func:`~werkzeug.utils.secure_filename` function actually do?
Now the problem is that there is that principle called "never trust user
input". This is also true for the filename of an uploaded file. All
submitted form data can be forged, and filenames can be dangerous. For
the moment just remember: always use that function to secure a filename
before storing it directly on the filesystem.
.. admonition:: Information for the Pros
So you're interested in what that :func:`~werkzeug.utils.secure_filename`
function does and what the problem is if you're not using it? So just
imagine someone would send the following information as `filename` to
your application::
filename = "../../../../home/username/.bashrc"
Assuming the number of ``../`` is correct and you would join this with
the ``UPLOAD_FOLDER`` the user might have the ability to modify a file on
the server's filesystem he or she should not modify. This does require some
knowledge about how the application looks like, but trust me, hackers
are patient :)
Now let's look how that function works:
>>> secure_filename('../../../../home/username/.bashrc')
'home_username_.bashrc'
We want to be able to serve the uploaded files so they can be downloaded
by users. We'll define a ``download_file`` view to serve files in the
upload folder by name. ``url_for("download_file", name=name)`` generates
download URLs.
.. code-block:: python
from flask import send_from_directory
@app.route('/uploads/<name>')
def download_file(name):
return send_from_directory(app.config["UPLOAD_FOLDER"], name)
If you're using middleware or the HTTP server to serve files, you can
register the ``download_file`` endpoint as ``build_only`` so ``url_for``
will work without a view function.
.. code-block:: python
app.add_url_rule(
"/uploads/<name>", endpoint="download_file", build_only=True
)
Improving Uploads
-----------------
.. versionadded:: 0.6
So how exactly does Flask handle uploads? Well it will store them in the
webserver's memory if the files are reasonably small, otherwise in a
temporary location (as returned by :func:`tempfile.gettempdir`). But how
do you specify the maximum file size after which an upload is aborted? By
default Flask will happily accept file uploads with an unlimited amount of
memory, but you can limit that by setting the ``MAX_CONTENT_LENGTH``
config key::
from flask import Flask, Request
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000
The code above will limit the maximum allowed payload to 16 megabytes.
If a larger file is transmitted, Flask will raise a
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception.
.. admonition:: Connection Reset Issue
When using the local development server, you may get a connection
reset error instead of a 413 response. You will get the correct
status response when running the app with a production WSGI server.
This feature was added in Flask 0.6 but can be achieved in older versions
as well by subclassing the request object. For more information on that
consult the Werkzeug documentation on file handling.
Upload Progress Bars
--------------------
A while ago many developers had the idea to read the incoming file in
small chunks and store the upload progress in the database to be able to
poll the progress with JavaScript from the client. The client asks the
server every 5 seconds how much it has transmitted, but this is
something it should already know.
An Easier Solution
------------------
Now there are better solutions that work faster and are more reliable. There
are JavaScript libraries like jQuery_ that have form plugins to ease the
construction of progress bar.
Because the common pattern for file uploads exists almost unchanged in all
applications dealing with uploads, there are also some Flask extensions that
implement a full fledged upload mechanism that allows controlling which
file extensions are allowed to be uploaded.
.. _jQuery: https://jquery.com/

@ -0,0 +1,148 @@
Message Flashing
================
Good applications and user interfaces are all about feedback. If the user
does not get enough feedback they will probably end up hating the
application. Flask provides a really simple way to give feedback to a
user with the flashing system. The flashing system basically makes it
possible to record a message at the end of a request and access it next
request and only next request. This is usually combined with a layout
template that does this. Note that browsers and sometimes web servers enforce
a limit on cookie sizes. This means that flashing messages that are too
large for session cookies causes message flashing to fail silently.
Simple Flashing
---------------
So here is a full example::
from flask import Flask, flash, redirect, render_template, \
request, url_for
app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or \
request.form['password'] != 'secret':
error = 'Invalid credentials'
else:
flash('You were successfully logged in')
return redirect(url_for('index'))
return render_template('login.html', error=error)
And here is the :file:`layout.html` template which does the magic:
.. sourcecode:: html+jinja
<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}
Here is the :file:`index.html` template which inherits from :file:`layout.html`:
.. sourcecode:: html+jinja
{% extends "layout.html" %}
{% block body %}
<h1>Overview</h1>
<p>Do you want to <a href="{{ url_for('login') }}">log in?</a>
{% endblock %}
And here is the :file:`login.html` template which also inherits from
:file:`layout.html`:
.. sourcecode:: html+jinja
{% extends "layout.html" %}
{% block body %}
<h1>Login</h1>
{% if error %}
<p class=error><strong>Error:</strong> {{ error }}
{% endif %}
<form method=post>
<dl>
<dt>Username:
<dd><input type=text name=username value="{{
request.form.username }}">
<dt>Password:
<dd><input type=password name=password>
</dl>
<p><input type=submit value=Login>
</form>
{% endblock %}
Flashing With Categories
------------------------
.. versionadded:: 0.3
It is also possible to provide categories when flashing a message. The
default category if nothing is provided is ``'message'``. Alternative
categories can be used to give the user better feedback. For example
error messages could be displayed with a red background.
To flash a message with a different category, just use the second argument
to the :func:`~flask.flash` function::
flash('Invalid password provided', 'error')
Inside the template you then have to tell the
:func:`~flask.get_flashed_messages` function to also return the
categories. The loop looks slightly different in that situation then:
.. sourcecode:: html+jinja
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class=flashes>
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
This is just one example of how to render these flashed messages. One
might also use the category to add a prefix such as
``<strong>Error:</strong>`` to the message.
Filtering Flash Messages
------------------------
.. versionadded:: 0.9
Optionally you can pass a list of categories which filters the results of
:func:`~flask.get_flashed_messages`. This is useful if you wish to
render each category in a separate block.
.. sourcecode:: html+jinja
{% with errors = get_flashed_messages(category_filter=["error"]) %}
{% if errors %}
<div class="alert-message block-message error">
<a class="close" href="#">×</a>
<ul>
{%- for msg in errors %}
<li>{{ msg }}</li>
{% endfor -%}
</ul>
</div>
{% endif %}
{% endwith %}

@ -0,0 +1,40 @@
Patterns for Flask
==================
Certain features and interactions are common enough that you will find
them in most web applications. For example, many applications use a
relational database and user authentication. They will open a database
connection at the beginning of the request and get the information for
the logged in user. At the end of the request, the database connection
is closed.
These types of patterns may be a bit outside the scope of Flask itself,
but Flask makes it easy to implement them. Some common patterns are
collected in the following pages.
.. toctree::
:maxdepth: 2
packages
appfactories
appdispatch
urlprocessors
sqlite3
sqlalchemy
fileuploads
caching
viewdecorators
wtforms
templateinheritance
flashing
javascript
lazyloading
mongoengine
favicon
streaming
deferredcallbacks
methodoverrides
requestchecksum
celery
subclassing
singlepageapplications

@ -0,0 +1,259 @@
JavaScript, ``fetch``, and JSON
===============================
You may want to make your HTML page dynamic, by changing data without
reloading the entire page. Instead of submitting an HTML ``<form>`` and
performing a redirect to re-render the template, you can add
`JavaScript`_ that calls |fetch|_ and replaces content on the page.
|fetch|_ is the modern, built-in JavaScript solution to making
requests from a page. You may have heard of other "AJAX" methods and
libraries, such as |XHR|_ or `jQuery`_. These are no longer needed in
modern browsers, although you may choose to use them or another library
depending on your application's requirements. These docs will only focus
on built-in JavaScript features.
.. _JavaScript: https://developer.mozilla.org/Web/JavaScript
.. |fetch| replace:: ``fetch()``
.. _fetch: https://developer.mozilla.org/Web/API/Fetch_API
.. |XHR| replace:: ``XMLHttpRequest()``
.. _XHR: https://developer.mozilla.org/Web/API/XMLHttpRequest
.. _jQuery: https://jquery.com/
Rendering Templates
-------------------
It is important to understand the difference between templates and
JavaScript. Templates are rendered on the server, before the response is
sent to the user's browser. JavaScript runs in the user's browser, after
the template is rendered and sent. Therefore, it is impossible to use
JavaScript to affect how the Jinja template is rendered, but it is
possible to render data into the JavaScript that will run.
To provide data to JavaScript when rendering the template, use the
:func:`~jinja-filters.tojson` filter in a ``<script>`` block. This will
convert the data to a valid JavaScript object, and ensure that any
unsafe HTML characters are rendered safely. If you do not use the
``tojson`` filter, you will get a ``SyntaxError`` in the browser
console.
.. code-block:: python
data = generate_report()
return render_template("report.html", chart_data=data)
.. code-block:: jinja
<script>
const chart_data = {{ chart_data|tojson }}
chartLib.makeChart(chart_data)
</script>
A less common pattern is to add the data to a ``data-`` attribute on an
HTML tag. In this case, you must use single quotes around the value, not
double quotes, otherwise you will produce invalid or unsafe HTML.
.. code-block:: jinja
<div data-chart='{{ chart_data|tojson }}'></div>
Generating URLs
---------------
The other way to get data from the server to JavaScript is to make a
request for it. First, you need to know the URL to request.
The simplest way to generate URLs is to continue to use
:func:`~flask.url_for` when rendering the template. For example:
.. code-block:: javascript
const user_url = {{ url_for("user", id=current_user.id)|tojson }}
fetch(user_url).then(...)
However, you might need to generate a URL based on information you only
know in JavaScript. As discussed above, JavaScript runs in the user's
browser, not as part of the template rendering, so you can't use
``url_for`` at that point.
In this case, you need to know the "root URL" under which your
application is served. In simple setups, this is ``/``, but it might
also be something else, like ``https://example.com/myapp/``.
A simple way to tell your JavaScript code about this root is to set it
as a global variable when rendering the template. Then you can use it
when generating URLs from JavaScript.
.. code-block:: javascript
const SCRIPT_ROOT = {{ request.script_root|tojson }}
let user_id = ... // do something to get a user id from the page
let user_url = `${SCRIPT_ROOT}/user/${user_id}`
fetch(user_url).then(...)
Making a Request with ``fetch``
-------------------------------
|fetch|_ takes two arguments, a URL and an object with other options,
and returns a |Promise|_. We won't cover all the available options, and
will only use ``then()`` on the promise, not other callbacks or
``await`` syntax. Read the linked MDN docs for more information about
those features.
By default, the GET method is used. If the response contains JSON, it
can be used with a ``then()`` callback chain.
.. code-block:: javascript
const room_url = {{ url_for("room_detail", id=room.id)|tojson }}
fetch(room_url)
.then(response => response.json())
.then(data => {
// data is a parsed JSON object
})
To send data, use a data method such as POST, and pass the ``body``
option. The most common types for data are form data or JSON data.
To send form data, pass a populated |FormData|_ object. This uses the
same format as an HTML form, and would be accessed with ``request.form``
in a Flask view.
.. code-block:: javascript
let data = new FormData()
data.append("name", "Flask Room")
data.append("description", "Talk about Flask here.")
fetch(room_url, {
"method": "POST",
"body": data,
}).then(...)
In general, prefer sending request data as form data, as would be used
when submitting an HTML form. JSON can represent more complex data, but
unless you need that it's better to stick with the simpler format. When
sending JSON data, the ``Content-Type: application/json`` header must be
sent as well, otherwise Flask will return a 400 error.
.. code-block:: javascript
let data = {
"name": "Flask Room",
"description": "Talk about Flask here.",
}
fetch(room_url, {
"method": "POST",
"headers": {"Content-Type": "application/json"},
"body": JSON.stringify(data),
}).then(...)
.. |Promise| replace:: ``Promise``
.. _Promise: https://developer.mozilla.org/Web/JavaScript/Reference/Global_Objects/Promise
.. |FormData| replace:: ``FormData``
.. _FormData: https://developer.mozilla.org/en-US/docs/Web/API/FormData
Following Redirects
-------------------
A response might be a redirect, for example if you logged in with
JavaScript instead of a traditional HTML form, and your view returned
a redirect instead of JSON. JavaScript requests do follow redirects, but
they don't change the page. If you want to make the page change you can
inspect the response and apply the redirect manually.
.. code-block:: javascript
fetch("/login", {"body": ...}).then(
response => {
if (response.redirected) {
window.location = response.url
} else {
showLoginError()
}
}
)
Replacing Content
-----------------
A response might be new HTML, either a new section of the page to add or
replace, or an entirely new page. In general, if you're returning the
entire page, it would be better to handle that with a redirect as shown
in the previous section. The following example shows how to replace a
``<div>`` with the HTML returned by a request.
.. code-block:: html
<div id="geology-fact">
{{ include "geology_fact.html" }}
</div>
<script>
const geology_url = {{ url_for("geology_fact")|tojson }}
const geology_div = getElementById("geology-fact")
fetch(geology_url)
.then(response => response.text)
.then(text => geology_div.innerHTML = text)
</script>
Return JSON from Views
----------------------
To return a JSON object from your API view, you can directly return a
dict from the view. It will be serialized to JSON automatically.
.. code-block:: python
@app.route("/user/<int:id>")
def user_detail(id):
user = User.query.get_or_404(id)
return {
"username": User.username,
"email": User.email,
"picture": url_for("static", filename=f"users/{id}/profile.png"),
}
If you want to return another JSON type, use the
:func:`~flask.json.jsonify` function, which creates a response object
with the given data serialized to JSON.
.. code-block:: python
from flask import jsonify
@app.route("/users")
def user_list():
users = User.query.order_by(User.name).all()
return jsonify([u.to_json() for u in users])
It is usually not a good idea to return file data in a JSON response.
JSON cannot represent binary data directly, so it must be base64
encoded, which can be slow, takes more bandwidth to send, and is not as
easy to cache. Instead, serve files using one view, and generate a URL
to the desired file to include in the JSON. Then the client can make a
separate request to get the linked resource after getting the JSON.
Receiving JSON in Views
-----------------------
Use the :attr:`~flask.Request.json` property of the
:data:`~flask.request` object to decode the request's body as JSON. If
the body is not valid JSON, or the ``Content-Type`` header is not set to
``application/json``, a 400 Bad Request error will be raised.
.. code-block:: python
from flask import request
@app.post("/user/<int:id>")
def user_update(id):
user = User.query.get_or_404(id)
user.update_from_json(request.json)
db.session.commit()
return user.to_json()

@ -0,0 +1,6 @@
:orphan:
AJAX with jQuery
================
Obsolete, see :doc:`/patterns/javascript` instead.

@ -0,0 +1,109 @@
Lazily Loading Views
====================
Flask is usually used with the decorators. Decorators are simple and you
have the URL right next to the function that is called for that specific
URL. However there is a downside to this approach: it means all your code
that uses decorators has to be imported upfront or Flask will never
actually find your function.
This can be a problem if your application has to import quick. It might
have to do that on systems like Google's App Engine or other systems. So
if you suddenly notice that your application outgrows this approach you
can fall back to a centralized URL mapping.
The system that enables having a central URL map is the
:meth:`~flask.Flask.add_url_rule` function. Instead of using decorators,
you have a file that sets up the application with all URLs.
Converting to Centralized URL Map
---------------------------------
Imagine the current application looks somewhat like this::
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
pass
@app.route('/user/<username>')
def user(username):
pass
Then, with the centralized approach you would have one file with the views
(:file:`views.py`) but without any decorator::
def index():
pass
def user(username):
pass
And then a file that sets up an application which maps the functions to
URLs::
from flask import Flask
from yourapplication import views
app = Flask(__name__)
app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/user/<username>', view_func=views.user)
Loading Late
------------
So far we only split up the views and the routing, but the module is still
loaded upfront. The trick is to actually load the view function as needed.
This can be accomplished with a helper class that behaves just like a
function but internally imports the real function on first use::
from werkzeug.utils import import_string, cached_property
class LazyView(object):
def __init__(self, import_name):
self.__module__, self.__name__ = import_name.rsplit('.', 1)
self.import_name = import_name
@cached_property
def view(self):
return import_string(self.import_name)
def __call__(self, *args, **kwargs):
return self.view(*args, **kwargs)
What's important here is is that `__module__` and `__name__` are properly
set. This is used by Flask internally to figure out how to name the
URL rules in case you don't provide a name for the rule yourself.
Then you can define your central place to combine the views like this::
from flask import Flask
from yourapplication.helpers import LazyView
app = Flask(__name__)
app.add_url_rule('/',
view_func=LazyView('yourapplication.views.index'))
app.add_url_rule('/user/<username>',
view_func=LazyView('yourapplication.views.user'))
You can further optimize this in terms of amount of keystrokes needed to
write this by having a function that calls into
:meth:`~flask.Flask.add_url_rule` by prefixing a string with the project
name and a dot, and by wrapping `view_func` in a `LazyView` as needed. ::
def url(import_name, url_rules=[], **options):
view = LazyView(f"yourapplication.{import_name}")
for url_rule in url_rules:
app.add_url_rule(url_rule, view_func=view, **options)
# add a single route to the index view
url('views.index', ['/'])
# add two routes to a single function endpoint
url_rules = ['/user/','/user/<username>']
url('views.user', url_rules)
One thing to keep in mind is that before and after request handlers have
to be in a file that is imported upfront to work properly on the first
request. The same goes for any kind of remaining decorator.

@ -0,0 +1,42 @@
Adding HTTP Method Overrides
============================
Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP
methods (such as PATCH). In that case it's possible to "proxy" HTTP
methods through another HTTP method in total violation of the protocol.
The way this works is by letting the client do an HTTP POST request and
set the ``X-HTTP-Method-Override`` header. Then the method is replaced
with the header value before being passed to Flask.
This can be accomplished with an HTTP middleware::
class HTTPMethodOverrideMiddleware(object):
allowed_methods = frozenset([
'GET',
'HEAD',
'POST',
'DELETE',
'PUT',
'PATCH',
'OPTIONS'
])
bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE'])
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper()
if method in self.allowed_methods:
environ['REQUEST_METHOD'] = method
if method in self.bodyless_methods:
environ['CONTENT_LENGTH'] = '0'
return self.app(environ, start_response)
To use this with Flask, wrap the app object with the middleware::
from flask import Flask
app = Flask(__name__)
app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app)

@ -0,0 +1,103 @@
MongoDB with MongoEngine
========================
Using a document database like MongoDB is a common alternative to
relational SQL databases. This pattern shows how to use
`MongoEngine`_, a document mapper library, to integrate with MongoDB.
A running MongoDB server and `Flask-MongoEngine`_ are required. ::
pip install flask-mongoengine
.. _MongoEngine: http://mongoengine.org
.. _Flask-MongoEngine: https://flask-mongoengine.readthedocs.io
Configuration
-------------
Basic setup can be done by defining ``MONGODB_SETTINGS`` on
``app.config`` and creating a ``MongoEngine`` instance. ::
from flask import Flask
from flask_mongoengine import MongoEngine
app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {
"db": "myapp",
}
db = MongoEngine(app)
Mapping Documents
-----------------
To declare a model that represents a Mongo document, create a class that
inherits from ``Document`` and declare each of the fields. ::
import mongoengine as me
class Movie(me.Document):
title = me.StringField(required=True)
year = me.IntField()
rated = me.StringField()
director = me.StringField()
actors = me.ListField()
If the document has nested fields, use ``EmbeddedDocument`` to
defined the fields of the embedded document and
``EmbeddedDocumentField`` to declare it on the parent document. ::
class Imdb(me.EmbeddedDocument):
imdb_id = me.StringField()
rating = me.DecimalField()
votes = me.IntField()
class Movie(me.Document):
...
imdb = me.EmbeddedDocumentField(Imdb)
Creating Data
-------------
Instantiate your document class with keyword arguments for the fields.
You can also assign values to the field attributes after instantiation.
Then call ``doc.save()``. ::
bttf = Movie(title="Back To The Future", year=1985)
bttf.actors = [
"Michael J. Fox",
"Christopher Lloyd"
]
bttf.imdb = Imdb(imdb_id="tt0088763", rating=8.5)
bttf.save()
Queries
-------
Use the class ``objects`` attribute to make queries. A keyword argument
looks for an equal value on the field. ::
bttf = Movie.objects(title="Back To The Future").get_or_404()
Query operators may be used by concatenating them with the field name
using a double-underscore. ``objects``, and queries returned by
calling it, are iterable. ::
some_theron_movie = Movie.objects(actors__in=["Charlize Theron"]).first()
for recents in Movie.objects(year__gte=2017):
print(recents.title)
Documentation
-------------
There are many more ways to define and query documents with MongoEngine.
For more information, check out the `official documentation
<MongoEngine_>`_.
Flask-MongoEngine adds helpful utilities on top of MongoEngine. Check
out their `documentation <Flask-MongoEngine_>`_ as well.

@ -0,0 +1,133 @@
Large Applications as Packages
==============================
Imagine a simple flask application structure that looks like this::
/yourapplication
yourapplication.py
/static
style.css
/templates
layout.html
index.html
login.html
...
While this is fine for small applications, for larger applications
it's a good idea to use a package instead of a module.
The :doc:`/tutorial/index` is structured to use the package pattern,
see the :gh:`example code <examples/tutorial>`.
Simple Packages
---------------
To convert that into a larger one, just create a new folder
:file:`yourapplication` inside the existing one and move everything below it.
Then rename :file:`yourapplication.py` to :file:`__init__.py`. (Make sure to delete
all ``.pyc`` files first, otherwise things would most likely break)
You should then end up with something like that::
/yourapplication
/yourapplication
__init__.py
/static
style.css
/templates
layout.html
index.html
login.html
...
But how do you run your application now? The naive ``python
yourapplication/__init__.py`` will not work. Let's just say that Python
does not want modules in packages to be the startup file. But that is not
a big problem, just add a new file called :file:`pyproject.toml` next to the inner
:file:`yourapplication` folder with the following contents:
.. code-block:: toml
[project]
name = "yourapplication"
dependencies = [
"flask",
]
[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"
Install your application so it is importable:
.. code-block:: text
$ pip install -e .
To use the ``flask`` command and run your application you need to set
the ``--app`` option that tells Flask where to find the application
instance:
.. code-block:: text
$ flask --app yourapplication run
What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the
following quick checklist:
1. the `Flask` application object creation has to be in the
:file:`__init__.py` file. That way each module can import it safely and the
`__name__` variable will resolve to the correct package.
2. all the view functions (the ones with a :meth:`~flask.Flask.route`
decorator on top) have to be imported in the :file:`__init__.py` file.
Not the object itself, but the module it is in. Import the view module
**after the application object is created**.
Here's an example :file:`__init__.py`::
from flask import Flask
app = Flask(__name__)
import yourapplication.views
And this is what :file:`views.py` would look like::
from yourapplication import app
@app.route('/')
def index():
return 'Hello World!'
You should then end up with something like that::
/yourapplication
pyproject.toml
/yourapplication
__init__.py
views.py
/static
style.css
/templates
layout.html
index.html
login.html
...
.. admonition:: Circular Imports
Every Python programmer hates them, and yet we just added some:
circular imports (That's when two modules depend on each other. In this
case :file:`views.py` depends on :file:`__init__.py`). Be advised that this is a
bad idea in general but here it is actually fine. The reason for this is
that we are not actually using the views in :file:`__init__.py` and just
ensuring the module is imported and we are doing that at the bottom of
the file.
Working with Blueprints
-----------------------
If you have larger applications it's recommended to divide them into
smaller groups where each group is implemented with the help of a
blueprint. For a gentle introduction into this topic refer to the
:doc:`/blueprints` chapter of the documentation.

@ -0,0 +1,55 @@
Request Content Checksums
=========================
Various pieces of code can consume the request data and preprocess it.
For instance JSON data ends up on the request object already read and
processed, form data ends up there as well but goes through a different
code path. This seems inconvenient when you want to calculate the
checksum of the incoming request data. This is necessary sometimes for
some APIs.
Fortunately this is however very simple to change by wrapping the input
stream.
The following example calculates the SHA1 checksum of the incoming data as
it gets read and stores it in the WSGI environment::
import hashlib
class ChecksumCalcStream(object):
def __init__(self, stream):
self._stream = stream
self._hash = hashlib.sha1()
def read(self, bytes):
rv = self._stream.read(bytes)
self._hash.update(rv)
return rv
def readline(self, size_hint):
rv = self._stream.readline(size_hint)
self._hash.update(rv)
return rv
def generate_checksum(request):
env = request.environ
stream = ChecksumCalcStream(env['wsgi.input'])
env['wsgi.input'] = stream
return stream._hash
To use this, all you need to do is to hook the calculating stream in
before the request starts consuming data. (Eg: be careful accessing
``request.form`` or anything of that nature. ``before_request_handlers``
for instance should be careful not to access it).
Example usage::
@app.route('/special-api', methods=['POST'])
def special_api():
hash = generate_checksum(request)
# Accessing this parses the input stream
files = request.files
# At this point the hash is fully constructed.
checksum = hash.hexdigest()
return f"Hash was: {checksum}"

@ -0,0 +1,24 @@
Single-Page Applications
========================
Flask can be used to serve Single-Page Applications (SPA) by placing static
files produced by your frontend framework in a subfolder inside of your
project. You will also need to create a catch-all endpoint that routes all
requests to your SPA.
The following example demonstrates how to serve an SPA along with an API::
from flask import Flask, jsonify
app = Flask(__name__, static_folder='app', static_url_path="/app")
@app.route("/heartbeat")
def heartbeat():
return jsonify({"status": "healthy"})
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return app.send_static_file("index.html")

@ -0,0 +1,213 @@
SQLAlchemy in Flask
===================
Many people prefer `SQLAlchemy`_ for database access. In this case it's
encouraged to use a package instead of a module for your flask application
and drop the models into a separate module (:doc:`packages`). While that
is not necessary, it makes a lot of sense.
There are four very common ways to use SQLAlchemy. I will outline each
of them here:
Flask-SQLAlchemy Extension
--------------------------
Because SQLAlchemy is a common database abstraction layer and object
relational mapper that requires a little bit of configuration effort,
there is a Flask extension that handles that for you. This is recommended
if you want to get started quickly.
You can download `Flask-SQLAlchemy`_ from `PyPI
<https://pypi.org/project/Flask-SQLAlchemy/>`_.
.. _Flask-SQLAlchemy: https://flask-sqlalchemy.palletsprojects.com/
Declarative
-----------
The declarative extension in SQLAlchemy is the most recent method of using
SQLAlchemy. It allows you to define tables and models in one go, similar
to how Django works. In addition to the following text I recommend the
official documentation on the `declarative`_ extension.
Here's the example :file:`database.py` module for your application::
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, declarative_base
engine = create_engine('sqlite:////tmp/test.db')
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
import yourapplication.models
Base.metadata.create_all(bind=engine)
To define your models, just subclass the `Base` class that was created by
the code above. If you are wondering why we don't have to care about
threads here (like we did in the SQLite3 example above with the
:data:`~flask.g` object): that's because SQLAlchemy does that for us
already with the :class:`~sqlalchemy.orm.scoped_session`.
To use SQLAlchemy in a declarative way with your application, you just
have to put the following code into your application module. Flask will
automatically remove database sessions at the end of the request or
when the application shuts down::
from yourapplication.database import db_session
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
Here is an example model (put this into :file:`models.py`, e.g.)::
from sqlalchemy import Column, Integer, String
from yourapplication.database import Base
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
email = Column(String(120), unique=True)
def __init__(self, name=None, email=None):
self.name = name
self.email = email
def __repr__(self):
return f'<User {self.name!r}>'
To create the database you can use the `init_db` function:
>>> from yourapplication.database import init_db
>>> init_db()
You can insert entries into the database like this:
>>> from yourapplication.database import db_session
>>> from yourapplication.models import User
>>> u = User('admin', 'admin@localhost')
>>> db_session.add(u)
>>> db_session.commit()
Querying is simple as well:
>>> User.query.all()
[<User 'admin'>]
>>> User.query.filter(User.name == 'admin').first()
<User 'admin'>
.. _SQLAlchemy: https://www.sqlalchemy.org/
.. _declarative: https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/
Manual Object Relational Mapping
--------------------------------
Manual object relational mapping has a few upsides and a few downsides
versus the declarative approach from above. The main difference is that
you define tables and classes separately and map them together. It's more
flexible but a little more to type. In general it works like the
declarative approach, so make sure to also split up your application into
multiple modules in a package.
Here is an example :file:`database.py` module for your application::
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('sqlite:////tmp/test.db')
metadata = MetaData()
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
def init_db():
metadata.create_all(bind=engine)
As in the declarative approach, you need to close the session after each app
context. Put this into your application module::
from yourapplication.database import db_session
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
Here is an example table and model (put this into :file:`models.py`)::
from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from yourapplication.database import metadata, db_session
class User(object):
query = db_session.query_property()
def __init__(self, name=None, email=None):
self.name = name
self.email = email
def __repr__(self):
return f'<User {self.name!r}>'
users = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50), unique=True),
Column('email', String(120), unique=True)
)
mapper(User, users)
Querying and inserting works exactly the same as in the example above.
SQL Abstraction Layer
---------------------
If you just want to use the database system (and SQL) abstraction layer
you basically only need the engine::
from sqlalchemy import create_engine, MetaData, Table
engine = create_engine('sqlite:////tmp/test.db')
metadata = MetaData(bind=engine)
Then you can either declare the tables in your code like in the examples
above, or automatically load them::
from sqlalchemy import Table
users = Table('users', metadata, autoload=True)
To insert data you can use the `insert` method. We have to get a
connection first so that we can use a transaction:
>>> con = engine.connect()
>>> con.execute(users.insert(), name='admin', email='admin@localhost')
SQLAlchemy will automatically commit for us.
To query your database, you use the engine directly or use a connection:
>>> users.select(users.c.id == 1).execute().first()
(1, 'admin', 'admin@localhost')
These results are also dict-like tuples:
>>> r = users.select(users.c.id == 1).execute().first()
>>> r['name']
'admin'
You can also pass strings of SQL statements to the
:meth:`~sqlalchemy.engine.base.Connection.execute` method:
>>> engine.execute('select * from users where id = :1', [1]).first()
(1, 'admin', 'admin@localhost')
For more information about SQLAlchemy, head over to the
`website <https://www.sqlalchemy.org/>`_.

@ -0,0 +1,147 @@
Using SQLite 3 with Flask
=========================
You can implement a few functions to work with a SQLite connection during a
request context. The connection is created the first time it's accessed,
reused on subsequent access, until it is closed when the request context ends.
Here is a simple example of how you can use SQLite 3 with Flask::
import sqlite3
from flask import g
DATABASE = '/path/to/database.db'
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
Now, to use the database, the application must either have an active
application context (which is always true if there is a request in flight)
or create an application context itself. At that point the ``get_db``
function can be used to get the current database connection. Whenever the
context is destroyed the database connection will be terminated.
Example::
@app.route('/')
def index():
cur = get_db().cursor()
...
.. note::
Please keep in mind that the teardown request and appcontext functions
are always executed, even if a before-request handler failed or was
never executed. Because of this we have to make sure here that the
database is there before we close it.
Connect on Demand
-----------------
The upside of this approach (connecting on first use) is that this will
only open the connection if truly necessary. If you want to use this
code outside a request context you can use it in a Python shell by opening
the application context by hand::
with app.app_context():
# now you can use get_db()
Easy Querying
-------------
Now in each request handling function you can access `get_db()` to get the
current open database connection. To simplify working with SQLite, a
row factory function is useful. It is executed for every result returned
from the database to convert the result. For instance, in order to get
dictionaries instead of tuples, this could be inserted into the ``get_db``
function we created above::
def make_dicts(cursor, row):
return dict((cursor.description[idx][0], value)
for idx, value in enumerate(row))
db.row_factory = make_dicts
This will make the sqlite3 module return dicts for this database connection, which are much nicer to deal with. Even more simply, we could place this in ``get_db`` instead::
db.row_factory = sqlite3.Row
This would use Row objects rather than dicts to return the results of queries. These are ``namedtuple`` s, so we can access them either by index or by key. For example, assuming we have a ``sqlite3.Row`` called ``r`` for the rows ``id``, ``FirstName``, ``LastName``, and ``MiddleInitial``::
>>> # You can get values based on the row's name
>>> r['FirstName']
John
>>> # Or, you can get them based on index
>>> r[1]
John
# Row objects are also iterable:
>>> for value in r:
... print(value)
1
John
Doe
M
Additionally, it is a good idea to provide a query function that combines
getting the cursor, executing and fetching the results::
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
This handy little function, in combination with a row factory, makes
working with the database much more pleasant than it is by just using the
raw cursor and connection objects.
Here is how you can use it::
for user in query_db('select * from users'):
print(user['username'], 'has the id', user['user_id'])
Or if you just want a single result::
user = query_db('select * from users where username = ?',
[the_username], one=True)
if user is None:
print('No such user')
else:
print(the_username, 'has the id', user['user_id'])
To pass variable parts to the SQL statement, use a question mark in the
statement and pass in the arguments as a list. Never directly add them to
the SQL statement with string formatting because this makes it possible
to attack the application using `SQL Injections
<https://en.wikipedia.org/wiki/SQL_injection>`_.
Initial Schemas
---------------
Relational databases need schemas, so applications often ship a
`schema.sql` file that creates the database. It's a good idea to provide
a function that creates the database based on that schema. This function
can do that for you::
def init_db():
with app.app_context():
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
You can then create such a database from the Python shell:
>>> from yourapplication import init_db
>>> init_db()

@ -0,0 +1,85 @@
Streaming Contents
==================
Sometimes you want to send an enormous amount of data to the client, much
more than you want to keep in memory. When you are generating the data on
the fly though, how do you send that back to the client without the
roundtrip to the filesystem?
The answer is by using generators and direct responses.
Basic Usage
-----------
This is a basic view function that generates a lot of CSV data on the fly.
The trick is to have an inner function that uses a generator to generate
data and to then invoke that function and pass it to a response object::
@app.route('/large.csv')
def generate_large_csv():
def generate():
for row in iter_all_rows():
yield f"{','.join(row)}\n"
return generate(), {"Content-Type": "text/csv"}
Each ``yield`` expression is directly sent to the browser. Note though
that some WSGI middlewares might break streaming, so be careful there in
debug environments with profilers and other things you might have enabled.
Streaming from Templates
------------------------
The Jinja template engine supports rendering a template piece by
piece, returning an iterator of strings. Flask provides the
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
functions to make this easier to use.
.. code-block:: python
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
The parts yielded by the render stream tend to match statement blocks in
the template.
Streaming with Context
----------------------
The :data:`.request` proxy will not be active while the generator is
running, because the app has already returned control to the WSGI server at that
point. If you try to access ``request``, you'll get a ``RuntimeError``.
If your generator function relies on data in ``request``, use the
:func:`.stream_with_context` wrapper. This will keep the request context active
during the generator.
.. code-block:: python
from flask import stream_with_context, request
from markupsafe import escape
@app.route('/stream')
def streamed_response():
def generate():
yield '<p>Hello '
yield escape(request.args['name'])
yield '!</p>'
return stream_with_context(generate())
It can also be used as a decorator.
.. code-block:: python
@stream_with_context
def generate():
...
return generate()
The :func:`~flask.stream_template` and
:func:`~flask.stream_template_string` functions automatically
use :func:`~flask.stream_with_context` if a request is active.

@ -0,0 +1,17 @@
Subclassing Flask
=================
The :class:`~flask.Flask` class is designed for subclassing.
For example, you may want to override how request parameters are handled to preserve their order::
from flask import Flask, Request
from werkzeug.datastructures import ImmutableOrderedMultiDict
class MyRequest(Request):
"""Request subclass to override request parameter storage"""
parameter_storage_class = ImmutableOrderedMultiDict
class MyFlask(Flask):
"""Flask subclass using the custom request class"""
request_class = MyRequest
This is the recommended approach for overriding or augmenting Flask's internal functionality.

@ -0,0 +1,68 @@
Template Inheritance
====================
The most powerful part of Jinja is template inheritance. Template inheritance
allows you to build a base "skeleton" template that contains all the common
elements of your site and defines **blocks** that child templates can override.
Sounds complicated but is very basic. It's easiest to understand it by starting
with an example.
Base Template
-------------
This template, which we'll call :file:`layout.html`, defines a simple HTML skeleton
document that you might use for a simple two-column page. It's the job of
"child" templates to fill the empty blocks with content:
.. sourcecode:: html+jinja
<!doctype html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
&copy; Copyright 2010 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
In this example, the ``{% block %}`` tags define four blocks that child templates
can fill in. All the `block` tag does is tell the template engine that a
child template may override those portions of the template.
Child Template
--------------
A child template might look like this:
.. sourcecode:: html+jinja
{% extends "layout.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome on my awesome homepage.
{% endblock %}
The ``{% extends %}`` tag is the key here. It tells the template engine that
this template "extends" another template. When the template system evaluates
this template, first it locates the parent. The extends tag must be the
first tag in the template. To render the contents of a block defined in
the parent template, use ``{{ super() }}``.

@ -0,0 +1,126 @@
Using URL Processors
====================
.. versionadded:: 0.7
Flask 0.7 introduces the concept of URL processors. The idea is that you
might have a bunch of resources with common parts in the URL that you
don't always explicitly want to provide. For instance you might have a
bunch of URLs that have the language code in it but you don't want to have
to handle it in every single function yourself.
URL processors are especially helpful when combined with blueprints. We
will handle both application specific URL processors here as well as
blueprint specifics.
Internationalized Application URLs
----------------------------------
Consider an application like this::
from flask import Flask, g
app = Flask(__name__)
@app.route('/<lang_code>/')
def index(lang_code):
g.lang_code = lang_code
...
@app.route('/<lang_code>/about')
def about(lang_code):
g.lang_code = lang_code
...
This is an awful lot of repetition as you have to handle the language code
setting on the :data:`~flask.g` object yourself in every single function.
Sure, a decorator could be used to simplify this, but if you want to
generate URLs from one function to another you would have to still provide
the language code explicitly which can be annoying.
For the latter, this is where :func:`~flask.Flask.url_defaults` functions
come in. They can automatically inject values into a call to
:func:`~flask.url_for`. The code below checks if the
language code is not yet in the dictionary of URL values and if the
endpoint wants a value named ``'lang_code'``::
@app.url_defaults
def add_language_code(endpoint, values):
if 'lang_code' in values or not g.lang_code:
return
if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
values['lang_code'] = g.lang_code
The method :meth:`~werkzeug.routing.Map.is_endpoint_expecting` of the URL
map can be used to figure out if it would make sense to provide a language
code for the given endpoint.
The reverse of that function are
:meth:`~flask.Flask.url_value_preprocessor`\s. They are executed right
after the request was matched and can execute code based on the URL
values. The idea is that they pull information out of the values
dictionary and put it somewhere else::
@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
g.lang_code = values.pop('lang_code', None)
That way you no longer have to do the `lang_code` assignment to
:data:`~flask.g` in every function. You can further improve that by
writing your own decorator that prefixes URLs with the language code, but
the more beautiful solution is using a blueprint. Once the
``'lang_code'`` is popped from the values dictionary and it will no longer
be forwarded to the view function reducing the code to this::
from flask import Flask, g
app = Flask(__name__)
@app.url_defaults
def add_language_code(endpoint, values):
if 'lang_code' in values or not g.lang_code:
return
if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
values['lang_code'] = g.lang_code
@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
g.lang_code = values.pop('lang_code', None)
@app.route('/<lang_code>/')
def index():
...
@app.route('/<lang_code>/about')
def about():
...
Internationalized Blueprint URLs
--------------------------------
Because blueprints can automatically prefix all URLs with a common string
it's easy to automatically do that for every function. Furthermore
blueprints can have per-blueprint URL processors which removes a whole lot
of logic from the :meth:`~flask.Flask.url_defaults` function because it no
longer has to check if the URL is really interested in a ``'lang_code'``
parameter::
from flask import Blueprint, g
bp = Blueprint('frontend', __name__, url_prefix='/<lang_code>')
@bp.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', g.lang_code)
@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
g.lang_code = values.pop('lang_code')
@bp.route('/')
def index():
...
@bp.route('/about')
def about():
...

@ -0,0 +1,171 @@
View Decorators
===============
Python has a really interesting feature called function decorators. This
allows some really neat things for web applications. Because each view in
Flask is a function, decorators can be used to inject additional
functionality to one or more functions. The :meth:`~flask.Flask.route`
decorator is the one you probably used already. But there are use cases
for implementing your own decorator. For instance, imagine you have a
view that should only be used by people that are logged in. If a user
goes to the site and is not logged in, they should be redirected to the
login page. This is a good example of a use case where a decorator is an
excellent solution.
Login Required Decorator
------------------------
So let's implement such a decorator. A decorator is a function that
wraps and replaces another function. Since the original function is
replaced, you need to remember to copy the original function's information
to the new function. Use :func:`functools.wraps` to handle this for you.
This example assumes that the login page is called ``'login'`` and that
the current user is stored in ``g.user`` and is ``None`` if there is no-one
logged in. ::
from functools import wraps
from flask import g, request, redirect, url_for
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for('login', next=request.url))
return f(*args, **kwargs)
return decorated_function
To use the decorator, apply it as innermost decorator to a view function.
When applying further decorators, always remember
that the :meth:`~flask.Flask.route` decorator is the outermost. ::
@app.route('/secret_page')
@login_required
def secret_page():
pass
.. note::
The ``next`` value will exist in ``request.args`` after a ``GET`` request for
the login page. You'll have to pass it along when sending the ``POST`` request
from the login form. You can do this with a hidden input tag, then retrieve it
from ``request.form`` when logging the user in. ::
<input type="hidden" value="{{ request.args.get('next', '') }}"/>
Caching Decorator
-----------------
Imagine you have a view function that does an expensive calculation and
because of that you would like to cache the generated results for a
certain amount of time. A decorator would be nice for that. We're
assuming you have set up a cache like mentioned in :doc:`caching`.
Here is an example cache function. It generates the cache key from a
specific prefix (actually a format string) and the current path of the
request. Notice that we are using a function that first creates the
decorator that then decorates the function. Sounds awful? Unfortunately
it is a little bit more complex, but the code should still be
straightforward to read.
The decorated function will then work as follows
1. get the unique cache key for the current request based on the current
path.
2. get the value for that key from the cache. If the cache returned
something we will return that value.
3. otherwise the original function is called and the return value is
stored in the cache for the timeout provided (by default 5 minutes).
Here the code::
from functools import wraps
from flask import request
def cached(timeout=5 * 60, key='view/{}'):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key.format(request.path)
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator
Notice that this assumes an instantiated ``cache`` object is available, see
:doc:`caching`.
Templating Decorator
--------------------
A common pattern invented by the TurboGears guys a while back is a
templating decorator. The idea of that decorator is that you return a
dictionary with the values passed to the template from the view function
and the template is automatically rendered. With that, the following
three examples do exactly the same::
@app.route('/')
def index():
return render_template('index.html', value=42)
@app.route('/')
@templated('index.html')
def index():
return dict(value=42)
@app.route('/')
@templated()
def index():
return dict(value=42)
As you can see, if no template name is provided it will use the endpoint
of the URL map with dots converted to slashes + ``'.html'``. Otherwise
the provided template name is used. When the decorated function returns,
the dictionary returned is passed to the template rendering function. If
``None`` is returned, an empty dictionary is assumed, if something else than
a dictionary is returned we return it from the function unchanged. That
way you can still use the redirect function or return simple strings.
Here is the code for that decorator::
from functools import wraps
from flask import request, render_template
def templated(template=None):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
template_name = template
if template_name is None:
template_name = f"{request.endpoint.replace('.', '/')}.html"
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}
elif not isinstance(ctx, dict):
return ctx
return render_template(template_name, **ctx)
return decorated_function
return decorator
Endpoint Decorator
------------------
When you want to use the werkzeug routing system for more flexibility you
need to map the endpoint as defined in the :class:`~werkzeug.routing.Rule`
to a view function. This is possible with this decorator. For example::
from flask import Flask
from werkzeug.routing import Rule
app = Flask(__name__)
app.url_map.add(Rule('/', endpoint='index'))
@app.endpoint('index')
def my_index():
return "Hello world"

@ -0,0 +1,126 @@
Form Validation with WTForms
============================
When you have to work with form data submitted by a browser view, code
quickly becomes very hard to read. There are libraries out there designed
to make this process easier to manage. One of them is `WTForms`_ which we
will handle here. If you find yourself in the situation of having many
forms, you might want to give it a try.
When you are working with WTForms you have to define your forms as classes
first. I recommend breaking up the application into multiple modules
(:doc:`packages`) for that and adding a separate module for the
forms.
.. admonition:: Getting the most out of WTForms with an Extension
The `Flask-WTF`_ extension expands on this pattern and adds a
few little helpers that make working with forms and Flask more
fun. You can get it from `PyPI
<https://pypi.org/project/Flask-WTF/>`_.
.. _Flask-WTF: https://flask-wtf.readthedocs.io/
The Forms
---------
This is an example form for a typical registration page::
from wtforms import Form, BooleanField, StringField, PasswordField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
In the View
-----------
In the view function, the usage of this form looks like this::
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
user = User(form.username.data, form.email.data,
form.password.data)
db_session.add(user)
flash('Thanks for registering')
return redirect(url_for('login'))
return render_template('register.html', form=form)
Notice we're implying that the view is using SQLAlchemy here
(:doc:`sqlalchemy`), but that's not a requirement, of course. Adapt
the code as necessary.
Things to remember:
1. create the form from the request :attr:`~flask.request.form` value if
the data is submitted via the HTTP ``POST`` method and
:attr:`~flask.request.args` if the data is submitted as ``GET``.
2. to validate the data, call the :func:`~wtforms.form.Form.validate`
method, which will return ``True`` if the data validates, ``False``
otherwise.
3. to access individual values from the form, access `form.<NAME>.data`.
Forms in Templates
------------------
Now to the template side. When you pass the form to the templates, you can
easily render them there. Look at the following example template to see
how easy this is. WTForms does half the form generation for us already.
To make it even nicer, we can write a macro that renders a field with
label and a list of errors if there are any.
Here's an example :file:`_formhelpers.html` template with such a macro:
.. sourcecode:: html+jinja
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
This macro accepts a couple of keyword arguments that are forwarded to
WTForm's field function, which renders the field for us. The keyword
arguments will be inserted as HTML attributes. So, for example, you can
call ``render_field(form.username, class='username')`` to add a class to
the input element. Note that WTForms returns standard Python strings,
so we have to tell Jinja that this data is already HTML-escaped with
the ``|safe`` filter.
Here is the :file:`register.html` template for the function we used above, which
takes advantage of the :file:`_formhelpers.html` template:
.. sourcecode:: html+jinja
{% from "_formhelpers.html" import render_field %}
<form method=post>
<dl>
{{ render_field(form.username) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm) }}
{{ render_field(form.accept_tos) }}
</dl>
<p><input type=submit value=Register>
</form>
For more information about WTForms, head over to the `WTForms
website`_.
.. _WTForms: https://wtforms.readthedocs.io/
.. _WTForms website: https://wtforms.readthedocs.io/

@ -0,0 +1,858 @@
Quickstart
==========
Eager to get started? This page gives a good introduction to Flask.
Follow :doc:`installation` to set up a project and install Flask first.
A Minimal Application
---------------------
A minimal Flask application looks something like this:
.. code-block:: python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
So what did that code do?
1. First we imported the :class:`~flask.Flask` class. An instance of
this class will be our WSGI application.
2. Next we create an instance of this class. The first argument is the
name of the application's module or package. ``__name__`` is a
convenient shortcut for this that is appropriate for most cases.
This is needed so that Flask knows where to look for resources such
as templates and static files.
3. We then use the :meth:`~flask.Flask.route` decorator to tell Flask
what URL should trigger our function.
4. The function returns the message we want to display in the user's
browser. The default content type is HTML, so HTML in the string
will be rendered by the browser.
Save it as :file:`hello.py` or something similar. Make sure to not call
your application :file:`flask.py` because this would conflict with Flask
itself.
To run the application, use the ``flask`` command or
``python -m flask``. You need to tell the Flask where your application
is with the ``--app`` option.
.. code-block:: text
$ flask --app hello run
* Serving Flask app 'hello'
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
.. admonition:: Application Discovery Behavior
As a shortcut, if the file is named ``app.py`` or ``wsgi.py``, you
don't have to use ``--app``. See :doc:`/cli` for more details.
This launches a very simple builtin server, which is good enough for
testing but probably not what you want to use in production. For
deployment options see :doc:`deploying/index`.
Now head over to http://127.0.0.1:5000/, and you should see your hello
world greeting.
If another program is already using port 5000, you'll see
``OSError: [Errno 98]`` or ``OSError: [WinError 10013]`` when the
server tries to start. See :ref:`address-already-in-use` for how to
handle that.
.. _public-server:
.. admonition:: Externally Visible Server
If you run the server you will notice that the server is only accessible
from your own computer, not from any other in the network. This is the
default because in debugging mode a user of the application can execute
arbitrary Python code on your computer.
If you have the debugger disabled or trust the users on your network,
you can make the server publicly available simply by adding
``--host=0.0.0.0`` to the command line::
$ flask run --host=0.0.0.0
This tells your operating system to listen on all public IPs.
Debug Mode
----------
The ``flask run`` command can do more than just start the development
server. By enabling debug mode, the server will automatically reload if
code changes, and will show an interactive debugger in the browser if an
error occurs during a request.
.. image:: _static/debugger.png
:align: center
:class: screenshot
:alt: The interactive debugger in action.
.. warning::
The debugger allows executing arbitrary Python code from the
browser. It is protected by a pin, but still represents a major
security risk. Do not run the development server or debugger in a
production environment.
To enable debug mode, use the ``--debug`` option.
.. code-block:: text
$ flask --app hello run --debug
* Serving Flask app 'hello'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: nnn-nnn-nnn
See also:
- :doc:`/server` and :doc:`/cli` for information about running in debug mode.
- :doc:`/debugging` for information about using the built-in debugger
and other debuggers.
- :doc:`/logging` and :doc:`/errorhandling` to log errors and display
nice error pages.
HTML Escaping
-------------
When returning HTML (the default response type in Flask), any
user-provided values rendered in the output must be escaped to protect
from injection attacks. HTML templates rendered with Jinja, introduced
later, will do this automatically.
:func:`~markupsafe.escape`, shown here, can be used manually. It is
omitted in most examples for brevity, but you should always be aware of
how you're using untrusted data.
.. code-block:: python
from flask import request
from markupsafe import escape
@app.route("/hello")
def hello():
name = request.args.get("name", "Flask")
return f"Hello, {escape(name)}!"
If a user submits ``/hello?name=<script>alert("bad")</script>``, escaping causes
it to be rendered as text, rather than running the script in the user's browser.
Routing
-------
Modern web applications use meaningful URLs to help users. Users are more
likely to like a page and come back if the page uses a meaningful URL they can
remember and use to directly visit a page.
Use the :meth:`~flask.Flask.route` decorator to bind a function to a URL. ::
@app.route('/')
def index():
return 'Index Page'
@app.route('/hello')
def hello():
return 'Hello, World'
You can do more! You can make parts of the URL dynamic and attach multiple
rules to a function.
Variable Rules
``````````````
You can add variable sections to a URL by marking sections with
``<variable_name>``. Your function then receives the ``<variable_name>``
as a keyword argument. Optionally, you can use a converter to specify the type
of the argument like ``<converter:variable_name>``. ::
from markupsafe import escape
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {escape(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}'
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {escape(subpath)}'
Converter types:
========== ==========================================
``string`` (default) accepts any text without a slash
``int`` accepts positive integers
``float`` accepts positive floating point values
``path`` like ``string`` but also accepts slashes
``uuid`` accepts UUID strings
========== ==========================================
Unique URLs / Redirection Behavior
``````````````````````````````````
The following two rules differ in their use of a trailing slash. ::
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
The canonical URL for the ``projects`` endpoint has a trailing slash.
It's similar to a folder in a file system. If you access the URL without
a trailing slash (``/projects``), Flask redirects you to the canonical URL
with the trailing slash (``/projects/``).
The canonical URL for the ``about`` endpoint does not have a trailing
slash. It's similar to the pathname of a file. Accessing the URL with a
trailing slash (``/about/``) produces a 404 "Not Found" error. This helps
keep URLs unique for these resources, which helps search engines avoid
indexing the same page twice.
.. _url-building:
URL Building
````````````
To build a URL to a specific function, use the :func:`~flask.url_for` function.
It accepts the name of the function as its first argument and any number of
keyword arguments, each corresponding to a variable part of the URL rule.
Unknown variable parts are appended to the URL as query parameters.
Why would you want to build URLs using the URL reversing function
:func:`~flask.url_for` instead of hard-coding them into your templates?
1. Reversing is often more descriptive than hard-coding the URLs.
2. You can change your URLs in one go instead of needing to remember to
manually change hard-coded URLs.
3. URL building handles escaping of special characters transparently.
4. The generated paths are always absolute, avoiding unexpected behavior
of relative paths in browsers.
5. If your application is placed outside the URL root, for example, in
``/myapplication`` instead of ``/``, :func:`~flask.url_for` properly
handles that for you.
For example, here we use the :meth:`~flask.Flask.test_request_context` method
to try out :func:`~flask.url_for`. :meth:`~flask.Flask.test_request_context`
tells Flask to behave as though it's handling a request even while we use a
Python shell. See :doc:`/appcontext`.
.. code-block:: python
from flask import url_for
@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'))
.. code-block:: text
/
/login
/login?next=/
/user/John%20Doe
HTTP Methods
````````````
Web applications use different HTTP methods when accessing URLs. You should
familiarize yourself with the HTTP methods as you work with Flask. By default,
a route only answers to ``GET`` requests. You can use the ``methods`` argument
of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods.
::
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
The example above keeps all methods for the route within one function,
which can be useful if each part uses some common data.
You can also separate views for different methods into different
functions. Flask provides a shortcut for decorating such routes with
:meth:`~flask.Flask.get`, :meth:`~flask.Flask.post`, etc. for each
common HTTP method.
.. code-block:: python
@app.get('/login')
def login_get():
return show_the_login_form()
@app.post('/login')
def login_post():
return do_the_login()
If ``GET`` is present, Flask automatically adds support for the ``HEAD`` method
and handles ``HEAD`` requests according to the `HTTP RFC`_. Likewise,
``OPTIONS`` is automatically implemented for you.
.. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt
Static Files
------------
Dynamic web applications also need static files. That's usually where
the CSS and JavaScript files are coming from. Ideally your web server is
configured to serve them for you, but during development Flask can do that
as well. Just create a folder called :file:`static` in your package or next to
your module and it will be available at ``/static`` on the application.
To generate URLs for static files, use the special ``'static'`` endpoint name::
url_for('static', filename='style.css')
The file has to be stored on the filesystem as :file:`static/style.css`.
Rendering Templates
-------------------
Generating HTML from within Python is not fun, and actually pretty
cumbersome because you have to do the HTML escaping on your own to keep
the application secure. Because of that Flask configures the `Jinja
<https://palletsprojects.com/p/jinja/>`_ template engine for you automatically.
Templates can be used to generate any type of text file. For web applications, you'll
primarily be generating HTML pages, but you can also generate markdown, plain text for
emails, and anything else.
For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_.
.. _MDN Web Docs: https://developer.mozilla.org/
To render a template you can use the :func:`~flask.render_template`
method. All you have to do is provide the name of the template and the
variables you want to pass to the template engine as keyword arguments.
Here's a simple example of how to render a template::
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', person=name)
Flask will look for templates in the :file:`templates` folder. So if your
application is a module, this folder is next to that module, if it's a
package it's actually inside your package:
**Case 1**: a module::
/application.py
/templates
/hello.html
**Case 2**: a package::
/application
/__init__.py
/templates
/hello.html
For templates you can use the full power of Jinja templates. Head over
to the official `Jinja Template Documentation
<https://jinja.palletsprojects.com/templates/>`_ for more information.
Here is an example template:
.. sourcecode:: html+jinja
<!doctype html>
<title>Hello from Flask</title>
{% if person %}
<h1>Hello {{ person }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
Inside templates you also have access to the :data:`~flask.Flask.config`,
:class:`~flask.request`, :class:`~flask.session` and :class:`~flask.g` [#]_ objects
as well as the :func:`~flask.url_for` and :func:`~flask.get_flashed_messages` functions.
Templates are especially useful if inheritance is used. If you want to
know how that works, see :doc:`patterns/templateinheritance`. Basically
template inheritance makes it possible to keep certain elements on each
page (like header, navigation and footer).
Automatic escaping is enabled, so if ``person`` contains HTML it will be escaped
automatically. If you can trust a variable and you know that it will be
safe HTML (for example because it came from a module that converts wiki
markup to HTML) you can mark it as safe by using the
:class:`~markupsafe.Markup` class or by using the ``|safe`` filter in the
template. Head over to the Jinja 2 documentation for more examples.
Here is a basic introduction to how the :class:`~markupsafe.Markup` class works::
>>> from markupsafe import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup('<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup('&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
'Marked up » HTML'
.. versionchanged:: 0.5
Autoescaping is no longer enabled for all templates. The following
extensions for templates trigger autoescaping: ``.html``, ``.htm``,
``.xml``, ``.xhtml``. Templates loaded from a string will have
autoescaping disabled.
.. [#] Unsure what that :class:`~flask.g` object is? It's something in which
you can store information for your own needs. See the documentation
for :class:`flask.g` and :doc:`patterns/sqlite3`.
Accessing Request Data
----------------------
For web applications it's crucial to react to the data a client sends to the
server. In Flask this information is provided by the global :data:`.request`
object, which is an instance of :class:`.Request`. This object has many
attributes and methods to work with the incoming request data, but here is a
broad overview. First it needs to be imported.
.. code-block:: python
from flask import request
If you have some experience with Python you might be wondering how that object
can be global when Flask handles multiple requests at a time. The answer is
that :data:`.request` is actually a proxy, pointing at whatever request is
currently being handled by a given worker, which is managed interanlly by Flask
and Python. See :doc:`/appcontext` for much more information.
The current request method is available in the :attr:`~.Request.method`
attribute. To access form data (data transmitted in a ``POST`` or ``PUT``
request), use the :attr:`~flask.Request.form` attribute, which behaves like a
dict.
.. code-block:: python
@app.route("/login", methods=["GET", "POST"])
def login():
error = None
if request.method == "POST":
if valid_login(request.form["username"], request.form["password"]):
return store_login(request.form["username"])
else:
error = "Invalid username or password"
# Executed if the request method was GET or the credentials were invalid.
return render_template("login.html", error=error)
If the key does not exist in ``form``, a special :exc:`KeyError` is raised. You
can catch it like a normal ``KeyError``, otherwise it will return a HTTP 400
Bad Request error page. You can also use the
:meth:`~werkzeug.datastructures.MultiDict.get` method to get a default
instead of an error.
To access parameters submitted in the URL (``?key=value``), use the
:attr:`~.Request.args` attribute. Key errors behave the same as ``form``,
returning a 400 response if not caught.
.. code-block:: python
searchword = request.args.get('key', '')
For a full list of methods and attributes of the request object, see the
:class:`~.Request` documentation.
File Uploads
````````````
You can handle uploaded files with Flask easily. Just make sure not to
forget to set the ``enctype="multipart/form-data"`` attribute on your HTML
form, otherwise the browser will not transmit your files at all.
Uploaded files are stored in memory or at a temporary location on the
filesystem. You can access those files by looking at the
:attr:`~flask.request.files` attribute on the request object. Each
uploaded file is stored in that dictionary. It behaves just like a
standard Python :class:`file` object, but it also has a
:meth:`~werkzeug.datastructures.FileStorage.save` method that
allows you to store that file on the filesystem of the server.
Here is a simple example showing how that works::
from flask import request
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/uploaded_file.txt')
...
If you want to know how the file was named on the client before it was
uploaded to your application, you can access the
:attr:`~werkzeug.datastructures.FileStorage.filename` attribute.
However please keep in mind that this value can be forged
so never ever trust that value. If you want to use the filename
of the client to store the file on the server, pass it through the
:func:`~werkzeug.utils.secure_filename` function that
Werkzeug provides for you::
from werkzeug.utils import secure_filename
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['the_file']
file.save(f"/var/www/uploads/{secure_filename(file.filename)}")
...
For some better examples, see :doc:`patterns/fileuploads`.
Cookies
```````
To access cookies you can use the :attr:`~flask.Request.cookies`
attribute. To set cookies you can use the
:attr:`~flask.Response.set_cookie` method of response objects. The
:attr:`~flask.Request.cookies` attribute of request objects is a
dictionary with all the cookies the client transmits. If you want to use
sessions, do not use the cookies directly but instead use the
:ref:`sessions` in Flask that add some security on top of cookies for you.
Reading cookies::
from flask import request
@app.route('/')
def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
Storing cookies::
from flask import make_response
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
Note that cookies are set on response objects. Since you normally
just return strings from the view functions Flask will convert them into
response objects for you. If you explicitly want to do that you can use
the :meth:`~flask.make_response` function and then modify it.
Sometimes you might want to set a cookie at a point where the response
object does not exist yet. This is possible by utilizing the
:doc:`patterns/deferredcallbacks` pattern.
For this also see :ref:`about-responses`.
Redirects and Errors
--------------------
To redirect a user to another endpoint, use the :func:`~flask.redirect`
function; to abort a request early with an error code, use the
:func:`~flask.abort` function::
from flask import abort, redirect, url_for
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
abort(401)
this_is_never_executed()
This is a rather pointless example because a user will be redirected from
the index to a page they cannot access (401 means access denied) but it
shows how that works.
By default a black and white error page is shown for each error code. If
you want to customize the error page, you can use the
:meth:`~flask.Flask.errorhandler` decorator::
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
Note the ``404`` after the :func:`~flask.render_template` call. This
tells Flask that the status code of that page should be 404 which means
not found. By default 200 is assumed which translates to: all went well.
See :doc:`errorhandling` for more details.
.. _about-responses:
About Responses
---------------
The return value from a view function is automatically converted into
a response object for you. If the return value is a string it's
converted into a response object with the string as response body, a
``200 OK`` status code and a :mimetype:`text/html` mimetype. If the
return value is a dict or list, :func:`jsonify` is called to produce a
response. The logic that Flask applies to converting return values into
response objects is as follows:
1. If a response object of the correct type is returned it's directly
returned from the view.
2. If it's a string, a response object is created with that data and
the default parameters.
3. If it's an iterator or generator returning strings or bytes, it is
treated as a streaming response.
4. If it's a dict or list, a response object is created using
:func:`~flask.json.jsonify`.
5. If a tuple is returned the items in the tuple can provide extra
information. Such tuples have to be in the form
``(response, status)``, ``(response, headers)``, or
``(response, status, headers)``. The ``status`` value will override
the status code and ``headers`` can be a list or dictionary of
additional header values.
6. If none of that works, Flask will assume the return value is a
valid WSGI application and convert that into a response object.
If you want to get hold of the resulting response object inside the view
you can use the :func:`~flask.make_response` function.
Imagine you have a view like this::
from flask import render_template
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
You just need to wrap the return expression with
:func:`~flask.make_response` and get the response object to modify it, then
return it::
from flask import make_response
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
APIs with JSON
``````````````
A common response format when writing an API is JSON. It's easy to get
started writing such an API with Flask. If you return a ``dict`` or
``list`` from a view, it will be converted to a JSON response.
.. code-block:: python
@app.route("/me")
def me_api():
user = get_current_user()
return {
"username": user.username,
"theme": user.theme,
"image": url_for("user_image", filename=user.image),
}
@app.route("/users")
def users_api():
users = get_all_users()
return [user.to_json() for user in users]
This is a shortcut to passing the data to the
:func:`~flask.json.jsonify` function, which will serialize any supported
JSON data type. That means that all the data in the dict or list must be
JSON serializable.
For complex types such as database models, you'll want to use a
serialization library to convert the data to valid JSON types first.
There are many serialization libraries and Flask API extensions
maintained by the community that support more complex applications.
.. _sessions:
Sessions
--------
In addition to the request object there is also a second object called
:class:`~flask.session` which allows you to store information specific to a
user from one request to the next. This is implemented on top of cookies
for you and signs the cookies cryptographically. What this means is that
the user could look at the contents of your cookie but not modify it,
unless they know the secret key used for signing.
In order to use sessions you have to set a secret key. Here is how
sessions work::
from flask import session
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
if 'username' in session:
return f'Logged in as {session["username"]}'
return 'You are not logged in'
@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():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
.. admonition:: How to generate good secret keys
A secret key should be as random as possible. Your operating system has
ways to generate pretty random data based on a cryptographic random
generator. Use the following command to quickly generate a value for
:attr:`Flask.secret_key` (or :data:`SECRET_KEY`)::
$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
A note on cookie-based sessions: Flask will take the values you put into the
session object and serialize them into a cookie. If you are finding some
values do not persist across requests, cookies are indeed enabled, and you are
not getting a clear error message, check the size of the cookie in your page
responses compared to the size supported by web browsers.
Besides the default client-side based sessions, if you want to handle
sessions on the server-side instead, there are several
Flask extensions that support this.
Message Flashing
----------------
Good applications and user interfaces are all about feedback. If the user
does not get enough feedback they will probably end up hating the
application. Flask provides a really simple way to give feedback to a
user with the flashing system. The flashing system basically makes it
possible to record a message at the end of a request and access it on the next
(and only the next) request. This is usually combined with a layout
template to expose the message.
To flash a message use the :func:`~flask.flash` method, to get hold of the
messages you can use :func:`~flask.get_flashed_messages` which is also
available in the templates. See :doc:`patterns/flashing` for a full
example.
Logging
-------
.. versionadded:: 0.3
Sometimes you might be in a situation where you deal with data that
should be correct, but actually is not. For example you may have
some client-side code that sends an HTTP request to the server
but it's obviously malformed. This might be caused by a user tampering
with the data, or the client code failing. Most of the time it's okay
to reply with ``400 Bad Request`` in that situation, but sometimes
that won't do and the code has to continue working.
You may still want to log that something fishy happened. This is where
loggers come in handy. As of Flask 0.3 a logger is preconfigured for you
to use.
Here are some example log calls::
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
The attached :attr:`~flask.Flask.logger` is a standard logging
:class:`~logging.Logger`, so head over to the official :mod:`logging`
docs for more information.
See :doc:`errorhandling`.
Hooking in WSGI Middleware
--------------------------
To add WSGI middleware to your Flask application, wrap the application's
``wsgi_app`` attribute. For example, to apply Werkzeug's
:class:`~werkzeug.middleware.proxy_fix.ProxyFix` middleware for running
behind Nginx:
.. code-block:: python
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)
Wrapping ``app.wsgi_app`` instead of ``app`` means that ``app`` still
points at your Flask application, not at the middleware, so you can
continue to use and configure ``app`` directly.
Using Flask Extensions
----------------------
Extensions are packages that help you accomplish common tasks. For
example, Flask-SQLAlchemy provides SQLAlchemy support that makes it simple
and easy to use with Flask.
For more on Flask extensions, see :doc:`extensions`.
Deploying to a Web Server
-------------------------
Ready to deploy your new Flask app? See :doc:`deploying/index`.

@ -0,0 +1,6 @@
:orphan:
The Request Context
===================
Obsolete, see :doc:`/appcontext` instead.

@ -0,0 +1,115 @@
.. currentmodule:: flask
Development Server
==================
Flask provides a ``run`` command to run the application with a development server. In
debug mode, this server provides an interactive debugger and will reload when code is
changed.
.. warning::
Do not use the development server when deploying to production. It
is intended for use only during local development. It is not
designed to be particularly efficient, stable, or secure.
See :doc:`/deploying/index` for deployment options.
Command Line
------------
The ``flask run`` CLI command is the recommended way to run the development server. Use
the ``--app`` option to point to your application, and the ``--debug`` option to enable
debug mode.
.. code-block:: text
$ flask --app hello run --debug
This enables debug mode, including the interactive debugger and reloader, and then
starts the server on http://localhost:5000/. Use ``flask run --help`` to see the
available options, and :doc:`/cli` for detailed instructions about configuring and using
the CLI.
.. _address-already-in-use:
Address already in use
~~~~~~~~~~~~~~~~~~~~~~
If another program is already using port 5000, you'll see an ``OSError``
when the server tries to start. It may have one of the following
messages:
- ``OSError: [Errno 98] Address already in use``
- ``OSError: [WinError 10013] An attempt was made to access a socket
in a way forbidden by its access permissions``
Either identify and stop the other program, or use
``flask run --port 5001`` to pick a different port.
You can use ``netstat`` or ``lsof`` to identify what process id is using
a port, then use other operating system tools stop that process. The
following example shows that process id 6847 is using port 5000.
.. tabs::
.. tab:: ``netstat`` (Linux)
.. code-block:: text
$ netstat -nlp | grep 5000
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN 6847/python
.. tab:: ``lsof`` (macOS / Linux)
.. code-block:: text
$ lsof -P -i :5000
Python 6847 IPv4 TCP localhost:5000 (LISTEN)
.. tab:: ``netstat`` (Windows)
.. code-block:: text
> netstat -ano | findstr 5000
TCP 127.0.0.1:5000 0.0.0.0:0 LISTENING 6847
macOS Monterey and later automatically starts a service that uses port
5000. You can choose to disable this service instead of using a different port by
searching for "AirPlay Receiver" in System Settings and toggling it off.
Deferred Errors on Reload
~~~~~~~~~~~~~~~~~~~~~~~~~
When using the ``flask run`` command with the reloader, the server will
continue to run even if you introduce syntax errors or other
initialization errors into the code. Accessing the site will show the
interactive debugger for the error, rather than crashing the server.
If a syntax error is already present when calling ``flask run``, it will
fail immediately and show the traceback rather than waiting until the
site is accessed. This is intended to make errors more visible initially
while still allowing the server to handle errors on reload.
In Code
-------
The development server can also be started from Python with the :meth:`Flask.run`
method. This method takes arguments similar to the CLI options to control the server.
The main difference from the CLI command is that the server will crash if there are
errors when reloading. ``debug=True`` can be passed to enable debug mode.
Place the call in a main block, otherwise it will interfere when trying to import and
run the application with a production server later.
.. code-block:: python
if __name__ == "__main__":
app.run(debug=True)
.. code-block:: text
$ python hello.py

@ -0,0 +1,81 @@
Working with the Shell
======================
One of the reasons everybody loves Python is the interactive shell. It allows
you to play around with code in real time and immediately get results back.
Flask provides the ``flask shell`` CLI command to start an interactive Python
shell with some setup done to make working with the Flask app easier.
.. code-block:: text
$ flask shell
Creating a Request Context
--------------------------
``flask shell`` pushes an app context automatically, so :data:`.current_app` and
:data:`.g` are already available. However, there is no HTTP request being
handled in the shell, so :data:`.request` and :data:`.session` are not yet
available.
The easiest way to create a proper request context from the shell is by
using the :attr:`~flask.Flask.test_request_context` method which creates
us a :class:`~flask.ctx.RequestContext`:
>>> ctx = app.test_request_context()
Normally you would use the ``with`` statement to make this context active, but
in the shell it's easier to call :meth:`~.RequestContext.push` and
:meth:`~.RequestContext.pop` manually:
>>> ctx.push()
From that point onwards you can work with the request object until you call
``pop``:
>>> ctx.pop()
Firing Before/After Request
---------------------------
By just creating a request context, you still don't have run the code that
is normally run before a request. This might result in your database
being unavailable if you are connecting to the database in a
before-request callback or the current user not being stored on the
:data:`~flask.g` object etc.
This however can easily be done yourself. Just call
:meth:`~flask.Flask.preprocess_request`:
>>> ctx = app.test_request_context()
>>> ctx.push()
>>> app.preprocess_request()
Keep in mind that the :meth:`~flask.Flask.preprocess_request` function
might return a response object, in that case just ignore it.
To shutdown a request, you need to trick a bit before the after request
functions (triggered by :meth:`~flask.Flask.process_response`) operate on
a response object:
>>> app.process_response(app.response_class())
<Response 0 bytes [200 OK]>
>>> ctx.pop()
The functions registered as :meth:`~flask.Flask.teardown_request` are
automatically called when the context is popped. So this is the perfect
place to automatically tear down resources that were needed by the request
context (such as database connections).
Further Improving the Shell Experience
--------------------------------------
If you like the idea of experimenting in a shell, create yourself a module
with stuff you want to star import into your interactive session. There
you could also define some more helper methods for common things such as
initializing the database, dropping tables etc.
Just put them into a module (like `shelltools`) and import from there:
>>> from shelltools import *

@ -0,0 +1,166 @@
Signals
=======
Signals are a lightweight way to notify subscribers of certain events during the
lifecycle of the application and each request. When an event occurs, it emits the
signal, which calls each subscriber.
Signals are implemented by the `Blinker`_ library. See its documentation for detailed
information. Flask provides some built-in signals. Extensions may provide their own.
Many signals mirror Flask's decorator-based callbacks with similar names. For example,
the :data:`.request_started` signal is similar to the :meth:`~.Flask.before_request`
decorator. The advantage of signals over handlers is that they can be subscribed to
temporarily, and can't directly affect the application. This is useful for testing,
metrics, auditing, and more. For example, if you want to know what templates were
rendered at what parts of what requests, there is a signal that will notify you of that
information.
Core Signals
------------
See :ref:`core-signals-list` for a list of all built-in signals. The :doc:`lifecycle`
page also describes the order that signals and decorators execute.
Subscribing to Signals
----------------------
To subscribe to a signal, you can use the
:meth:`~blinker.base.Signal.connect` method of a signal. The first
argument is the function that should be called when the signal is emitted,
the optional second argument specifies a sender. To unsubscribe from a
signal, you can use the :meth:`~blinker.base.Signal.disconnect` method.
For all core Flask signals, the sender is the application that issued the
signal. When you subscribe to a signal, be sure to also provide a sender
unless you really want to listen for signals from all applications. This is
especially true if you are developing an extension.
For example, here is a helper context manager that can be used in a unit test
to determine which templates were rendered and what variables were passed
to the template::
from flask import template_rendered
from contextlib import contextmanager
@contextmanager
def captured_templates(app):
recorded = []
def record(sender, template, context, **extra):
recorded.append((template, context))
template_rendered.connect(record, app)
try:
yield recorded
finally:
template_rendered.disconnect(record, app)
This can now easily be paired with a test client::
with captured_templates(app) as templates:
rv = app.test_client().get('/')
assert rv.status_code == 200
assert len(templates) == 1
template, context = templates[0]
assert template.name == 'index.html'
assert len(context['items']) == 10
Make sure to subscribe with an extra ``**extra`` argument so that your
calls don't fail if Flask introduces new arguments to the signals.
All the template rendering in the code issued by the application `app`
in the body of the ``with`` block will now be recorded in the `templates`
variable. Whenever a template is rendered, the template object as well as
context are appended to it.
Additionally there is a convenient helper method
(:meth:`~blinker.base.Signal.connected_to`) that allows you to
temporarily subscribe a function to a signal with a context manager on
its own. Because the return value of the context manager cannot be
specified that way, you have to pass the list in as an argument::
from flask import template_rendered
def captured_templates(app, recorded, **extra):
def record(sender, template, context):
recorded.append((template, context))
return template_rendered.connected_to(record, app)
The example above would then look like this::
templates = []
with captured_templates(app, templates, **extra):
...
template, context = templates[0]
Creating Signals
----------------
If you want to use signals in your own application, you can use the
blinker library directly. The most common use case are named signals in a
custom :class:`~blinker.base.Namespace`. This is what is recommended
most of the time::
from blinker import Namespace
my_signals = Namespace()
Now you can create new signals like this::
model_saved = my_signals.signal('model-saved')
The name for the signal here makes it unique and also simplifies
debugging. You can access the name of the signal with the
:attr:`~blinker.base.NamedSignal.name` attribute.
.. _signals-sending:
Sending Signals
---------------
If you want to emit a signal, you can do so by calling the
:meth:`~blinker.base.Signal.send` method. It accepts a sender as first
argument and optionally some keyword arguments that are forwarded to the
signal subscribers::
class Model(object):
...
def save(self):
model_saved.send(self)
Try to always pick a good sender. If you have a class that is emitting a
signal, pass ``self`` as sender. If you are emitting a signal from a random
function, you can pass ``current_app._get_current_object()`` as sender.
.. admonition:: Passing Proxies as Senders
Never pass :data:`~flask.current_app` as sender to a signal. Use
``current_app._get_current_object()`` instead. The reason for this is
that :data:`~flask.current_app` is a proxy and not the real application
object.
Signals and Flask's Request Context
-----------------------------------
Context-local proxies are available between :data:`~flask.request_started` and
:data:`~flask.request_finished`, so you can rely on :class:`flask.g` and others
as needed. Note the limitations described in :ref:`signals-sending` and the
:data:`~flask.request_tearing_down` signal.
Decorator Based Signal Subscriptions
------------------------------------
You can also easily subscribe to signals by using the
:meth:`~blinker.base.NamedSignal.connect_via` decorator::
from flask import template_rendered
@template_rendered.connect_via(app)
def when_template_rendered(sender, template, context, **extra):
print(f'Template {template.name} is rendered with {context}')
.. _blinker: https://pypi.org/project/blinker/

@ -0,0 +1,255 @@
Templates
=========
Flask leverages Jinja as its template engine. You are obviously free to use
a different template engine, but you still have to install Jinja to run
Flask itself. This requirement is necessary to enable rich extensions.
An extension can depend on Jinja being present.
This section only gives a very quick introduction into how Jinja
is integrated into Flask. If you want information on the template
engine's syntax itself, head over to the official `Jinja Template
Documentation <https://jinja.palletsprojects.com/templates/>`_ for
more information.
Jinja Setup
-----------
Unless customized, Jinja is configured by Flask as follows:
- autoescaping is enabled for all templates ending in ``.html``,
``.htm``, ``.xml``, ``.xhtml``, as well as ``.svg`` when using
:func:`~flask.templating.render_template`.
- autoescaping is enabled for all strings when using
:func:`~flask.templating.render_template_string`.
- a template has the ability to opt in/out autoescaping with the
``{% autoescape %}`` tag.
- Flask inserts a couple of global functions and helpers into the
Jinja context, additionally to the values that are present by
default.
Standard Context
----------------
The following global variables are available within Jinja templates
by default:
.. data:: config
:noindex:
The current configuration object (:data:`flask.Flask.config`)
.. versionadded:: 0.6
.. versionchanged:: 0.10
This is now always available, even in imported templates.
.. data:: request
:noindex:
The current request object (:class:`flask.request`). This variable is
unavailable if the template was rendered without an active request
context.
.. data:: session
:noindex:
The current session object (:class:`flask.session`). This variable
is unavailable if the template was rendered without an active request
context.
.. data:: g
:noindex:
The request-bound object for global variables (:data:`flask.g`). This
variable is unavailable if the template was rendered without an active
request context.
.. function:: url_for
:noindex:
The :func:`flask.url_for` function.
.. function:: get_flashed_messages
:noindex:
The :func:`flask.get_flashed_messages` function.
.. admonition:: The Jinja Context Behavior
These variables are added to the context of variables, they are not
global variables. The difference is that by default these will not
show up in the context of imported templates. This is partially caused
by performance considerations, partially to keep things explicit.
What does this mean for you? If you have a macro you want to import,
that needs to access the request object you have two possibilities:
1. you explicitly pass the request to the macro as parameter, or
the attribute of the request object you are interested in.
2. you import the macro "with context".
Importing with context looks like this:
.. sourcecode:: jinja
{% from '_helpers.html' import my_macro with context %}
Controlling Autoescaping
------------------------
Autoescaping is the concept of automatically escaping special characters
for you. Special characters in the sense of HTML (or XML, and thus XHTML)
are ``&``, ``>``, ``<``, ``"`` as well as ``'``. Because these characters
carry specific meanings in documents on their own you have to replace them
by so called "entities" if you want to use them for text. Not doing so
would not only cause user frustration by the inability to use these
characters in text, but can also lead to security problems. (see
:ref:`security-xss`)
Sometimes however you will need to disable autoescaping in templates.
This can be the case if you want to explicitly inject HTML into pages, for
example if they come from a system that generates secure HTML like a
markdown to HTML converter.
There are three ways to accomplish that:
- In the Python code, wrap the HTML string in a :class:`~markupsafe.Markup`
object before passing it to the template. This is in general the
recommended way.
- Inside the template, use the ``|safe`` filter to explicitly mark a
string as safe HTML (``{{ myvariable|safe }}``)
- Temporarily disable the autoescape system altogether.
To disable the autoescape system in templates, you can use the ``{%
autoescape %}`` block:
.. sourcecode:: html+jinja
{% autoescape false %}
<p>autoescaping is disabled here
<p>{{ will_not_be_escaped }}
{% endautoescape %}
Whenever you do this, please be very cautious about the variables you are
using in this block.
.. _registering-filters:
Registering Filters, Tests, and Globals
---------------------------------------
The Flask app and blueprints provide decorators and methods to register your own
filters, tests, and global functions for use in Jinja templates. They all follow
the same pattern, so the following examples only discuss filters.
Decorate a function with :meth:`~.Flask.template_filter` to register it as a
template filter.
.. code-block:: python
@app.template_filter
def reverse(s):
return reversed(s)
.. code-block:: jinja
{% for item in data | reverse %}
{% endfor %}
By default it will use the name of the function as the name of the filter, but
that can be changed by passing a name to the decorator.
.. code-block:: python
@app.template_filter("reverse")
def reverse_filter(s):
return reversed(s)
A filter can be registered separately using :meth:`~.Flask.add_template_filter`.
The name is optional and will use the function name if not given.
.. code-block:: python
def reverse_filter(s):
return reversed(s)
app.add_template_filter(reverse_filter, "reverse")
For template tests, use the :meth:`~.Flask.template_test` decorator or
:meth:`~.Flask.add_template_test` method. For template global functions, use the
:meth:`~.Flask.template_global` decorator or :meth:`~.Flask.add_template_global`
method.
The same methods also exist on :class:`.Blueprint`, prefixed with ``app_`` to
indicate that the registered functions will be avaialble to all templates, not
only when rendering from within the blueprint.
The Jinja environment is also available as :attr:`~.Flask.jinja_env`. It may be
modified directly, as you would when using Jinja outside Flask.
Context Processors
------------------
To inject new variables automatically into the context of a template,
context processors exist in Flask. Context processors run before the
template is rendered and have the ability to inject new values into the
template context. A context processor is a function that returns a
dictionary. The keys and values of this dictionary are then merged with
the template context, for all templates in the app::
@app.context_processor
def inject_user():
return dict(user=g.user)
The context processor above makes a variable called `user` available in
the template with the value of `g.user`. This example is not very
interesting because `g` is available in templates anyways, but it gives an
idea how this works.
Variables are not limited to values; a context processor can also make
functions available to templates (since Python allows passing around
functions)::
@app.context_processor
def utility_processor():
def format_price(amount, currency="€"):
return f"{amount:.2f}{currency}"
return dict(format_price=format_price)
The context processor above makes the `format_price` function available to all
templates::
{{ format_price(0.33) }}
You could also build `format_price` as a template filter (see
:ref:`registering-filters`), but this demonstrates how to pass functions in a
context processor.
Streaming
---------
It can be useful to not render the whole template as one complete
string, instead render it as a stream, yielding smaller incremental
strings. This can be used for streaming HTML in chunks to speed up
initial page load, or to save memory when rendering a very large
template.
The Jinja template engine supports rendering a template piece
by piece, returning an iterator of strings. Flask provides the
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
functions to make this easier to use.
.. code-block:: python
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
These functions automatically apply the
:func:`~flask.stream_with_context` wrapper if a request is active, so
that it remains available in the template.

@ -0,0 +1,318 @@
Testing Flask Applications
==========================
Flask provides utilities for testing an application. This documentation
goes over techniques for working with different parts of the application
in tests.
We will use the `pytest`_ framework to set up and run our tests.
.. code-block:: text
$ pip install pytest
.. _pytest: https://docs.pytest.org/
The :doc:`tutorial </tutorial/index>` goes over how to write tests for
100% coverage of the sample Flaskr blog application. See
:doc:`the tutorial on tests </tutorial/tests>` for a detailed
explanation of specific tests for an application.
Identifying Tests
-----------------
Tests are typically located in the ``tests`` folder. Tests are functions
that start with ``test_``, in Python modules that start with ``test_``.
Tests can also be further grouped in classes that start with ``Test``.
It can be difficult to know what to test. Generally, try to test the
code that you write, not the code of libraries that you use, since they
are already tested. Try to extract complex behaviors as separate
functions to test individually.
Fixtures
--------
Pytest *fixtures* allow writing pieces of code that are reusable across
tests. A simple fixture returns a value, but a fixture can also do
setup, yield a value, then do teardown. Fixtures for the application,
test client, and CLI runner are shown below, they can be placed in
``tests/conftest.py``.
If you're using an
:doc:`application factory </patterns/appfactories>`, define an ``app``
fixture to create and configure an app instance. You can add code before
and after the ``yield`` to set up and tear down other resources, such as
creating and clearing a database.
If you're not using a factory, you already have an app object you can
import and configure directly. You can still use an ``app`` fixture to
set up and tear down resources.
.. code-block:: python
import pytest
from my_project import create_app
@pytest.fixture()
def app():
app = create_app()
app.config.update({
"TESTING": True,
})
# other setup can go here
yield app
# clean up / reset resources here
@pytest.fixture()
def client(app):
return app.test_client()
@pytest.fixture()
def runner(app):
return app.test_cli_runner()
Sending Requests with the Test Client
-------------------------------------
The test client makes requests to the application without running a live
server. Flask's client extends
:doc:`Werkzeug's client <werkzeug:test>`, see those docs for additional
information.
The ``client`` has methods that match the common HTTP request methods,
such as ``client.get()`` and ``client.post()``. They take many arguments
for building the request; you can find the full documentation in
:class:`~werkzeug.test.EnvironBuilder`. Typically you'll use ``path``,
``query_string``, ``headers``, and ``data`` or ``json``.
To make a request, call the method the request should use with the path
to the route to test. A :class:`~werkzeug.test.TestResponse` is returned
to examine the response data. It has all the usual properties of a
response object. You'll usually look at ``response.data``, which is the
bytes returned by the view. If you want to use text, Werkzeug 2.1
provides ``response.text``, or use ``response.get_data(as_text=True)``.
.. code-block:: python
def test_request_example(client):
response = client.get("/posts")
assert b"<h2>Hello, World!</h2>" in response.data
Pass a dict ``query_string={"key": "value", ...}`` to set arguments in
the query string (after the ``?`` in the URL). Pass a dict
``headers={}`` to set request headers.
To send a request body in a POST or PUT request, pass a value to
``data``. If raw bytes are passed, that exact body is used. Usually,
you'll pass a dict to set form data.
Form Data
~~~~~~~~~
To send form data, pass a dict to ``data``. The ``Content-Type`` header
will be set to ``multipart/form-data`` or
``application/x-www-form-urlencoded`` automatically.
If a value is a file object opened for reading bytes (``"rb"`` mode), it
will be treated as an uploaded file. To change the detected filename and
content type, pass a ``(file, filename, content_type)`` tuple. File
objects will be closed after making the request, so they do not need to
use the usual ``with open() as f:`` pattern.
It can be useful to store files in a ``tests/resources`` folder, then
use ``pathlib.Path`` to get files relative to the current test file.
.. code-block:: python
from pathlib import Path
# get the resources folder in the tests folder
resources = Path(__file__).parent / "resources"
def test_edit_user(client):
response = client.post("/user/2/edit", data={
"name": "Flask",
"theme": "dark",
"picture": (resources / "picture.png").open("rb"),
})
assert response.status_code == 200
JSON Data
~~~~~~~~~
To send JSON data, pass an object to ``json``. The ``Content-Type``
header will be set to ``application/json`` automatically.
Similarly, if the response contains JSON data, the ``response.json``
attribute will contain the deserialized object.
.. code-block:: python
def test_json_data(client):
response = client.post("/graphql", json={
"query": """
query User($id: String!) {
user(id: $id) {
name
theme
picture_url
}
}
""",
variables={"id": 2},
})
assert response.json["data"]["user"]["name"] == "Flask"
Following Redirects
-------------------
By default, the client does not make additional requests if the response
is a redirect. By passing ``follow_redirects=True`` to a request method,
the client will continue to make requests until a non-redirect response
is returned.
:attr:`TestResponse.history <werkzeug.test.TestResponse.history>` is
a tuple of the responses that led up to the final response. Each
response has a :attr:`~werkzeug.test.TestResponse.request` attribute
which records the request that produced that response.
.. code-block:: python
def test_logout_redirect(client):
response = client.get("/logout", follow_redirects=True)
# Check that there was one redirect response.
assert len(response.history) == 1
# Check that the second request was to the index page.
assert response.request.path == "/index"
Accessing and Modifying the Session
-----------------------------------
To access Flask's context variables, mainly
:data:`~flask.session`, use the client in a ``with`` statement.
The app and request context will remain active *after* making a request,
until the ``with`` block ends.
.. code-block:: python
from flask import session
def test_access_session(client):
with client:
client.post("/auth/login", data={"username": "flask"})
# session is still accessible
assert session["user_id"] == 1
# session is no longer accessible
If you want to access or set a value in the session *before* making a
request, use the client's
:meth:`~flask.testing.FlaskClient.session_transaction` method in a
``with`` statement. It returns a session object, and will save the
session once the block ends.
.. code-block:: python
from flask import session
def test_modify_session(client):
with client.session_transaction() as session:
# set a user id without going through the login route
session["user_id"] = 1
# session is saved now
response = client.get("/users/me")
assert response.json["username"] == "flask"
.. _testing-cli:
Running Commands with the CLI Runner
------------------------------------
Flask provides :meth:`~flask.Flask.test_cli_runner` to create a
:class:`~flask.testing.FlaskCliRunner`, which runs CLI commands in
isolation and captures the output in a :class:`~click.testing.Result`
object. Flask's runner extends :doc:`Click's runner <click:testing>`,
see those docs for additional information.
Use the runner's :meth:`~flask.testing.FlaskCliRunner.invoke` method to
call commands in the same way they would be called with the ``flask``
command from the command line.
.. code-block:: python
import click
@app.cli.command("hello")
@click.option("--name", default="World")
def hello_command(name):
click.echo(f"Hello, {name}!")
def test_hello_command(runner):
result = runner.invoke(args="hello")
assert "World" in result.output
result = runner.invoke(args=["hello", "--name", "Flask"])
assert "Flask" in result.output
Tests that depend on an Active Context
--------------------------------------
You may have functions that are called from views or commands, that expect an
active :doc:`app context </appcontext>` because they access :data:`.request`,
:data:`.session`, :data:`.g`, or :data:`.current_app`. Rather than testing them by
making a request or invoking the command, you can create and activate a context
directly.
Use ``with app.app_context()`` to push an application context. For
example, database extensions usually require an active app context to
make queries.
.. code-block:: python
def test_db_post_model(app):
with app.app_context():
post = db.session.query(Post).get(1)
Use ``with app.test_request_context()`` to push a request context. It
takes the same arguments as the test client's request methods.
.. code-block:: python
def test_validate_user_edit(app):
with app.test_request_context(
"/user/2/edit", method="POST", data={"name": ""}
):
# call a function that accesses `request`
messages = validate_edit_user()
assert messages["name"][0] == "Name cannot be empty."
Creating a test request context doesn't run any of the Flask dispatching
code, so ``before_request`` functions are not called. If you need to
call these, usually it's better to make a full request instead. However,
it's possible to call them manually.
.. code-block:: python
def test_auth_token(app):
with app.test_request_context("/user/2/edit", headers={"X-Auth-Token": "1"}):
app.preprocess_request()
assert g.user.name == "Flask"

@ -0,0 +1,336 @@
.. currentmodule:: flask
Blog Blueprint
==============
You'll use the same techniques you learned about when writing the
authentication blueprint to write the blog blueprint. The blog should
list all posts, allow logged in users to create posts, and allow the
author of a post to edit or delete it.
As you implement each view, keep the development server running. As you
save your changes, try going to the URL in your browser and testing them
out.
The Blueprint
-------------
Define the blueprint and register it in the application factory.
.. code-block:: python
:caption: ``flaskr/blog.py``
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
from flaskr.auth import login_required
from flaskr.db import get_db
bp = Blueprint('blog', __name__)
Import and register the blueprint from the factory using
:meth:`app.register_blueprint() <Flask.register_blueprint>`. Place the
new code at the end of the factory function before returning the app.
.. code-block:: python
:caption: ``flaskr/__init__.py``
def create_app():
app = ...
# existing code omitted
from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule('/', endpoint='index')
return app
Unlike the auth blueprint, the blog blueprint does not have a
``url_prefix``. So the ``index`` view will be at ``/``, the ``create``
view at ``/create``, and so on. The blog is the main feature of Flaskr,
so it makes sense that the blog index will be the main index.
However, the endpoint for the ``index`` view defined below will be
``blog.index``. Some of the authentication views referred to a plain
``index`` endpoint. :meth:`app.add_url_rule() <Flask.add_url_rule>`
associates the endpoint name ``'index'`` with the ``/`` url so that
``url_for('index')`` or ``url_for('blog.index')`` will both work,
generating the same ``/`` URL either way.
In another application you might give the blog blueprint a
``url_prefix`` and define a separate ``index`` view in the application
factory, similar to the ``hello`` view. Then the ``index`` and
``blog.index`` endpoints and URLs would be different.
Index
-----
The index will show all of the posts, most recent first. A ``JOIN`` is
used so that the author information from the ``user`` table is
available in the result.
.. code-block:: python
:caption: ``flaskr/blog.py``
@bp.route('/')
def index():
db = get_db()
posts = db.execute(
'SELECT p.id, title, body, created, author_id, username'
' FROM post p JOIN user u ON p.author_id = u.id'
' ORDER BY created DESC'
).fetchall()
return render_template('blog/index.html', posts=posts)
.. code-block:: html+jinja
:caption: ``flaskr/templates/blog/index.html``
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Posts{% endblock %}</h1>
{% if g.user %}
<a class="action" href="{{ url_for('blog.create') }}">New</a>
{% endif %}
{% endblock %}
{% block content %}
{% for post in posts %}
<article class="post">
<header>
<div>
<h1>{{ post['title'] }}</h1>
<div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}</div>
</div>
{% if g.user['id'] == post['author_id'] %}
<a class="action" href="{{ url_for('blog.update', id=post['id']) }}">Edit</a>
{% endif %}
</header>
<p class="body">{{ post['body'] }}</p>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
When a user is logged in, the ``header`` block adds a link to the
``create`` view. When the user is the author of a post, they'll see an
"Edit" link to the ``update`` view for that post. ``loop.last`` is a
special variable available inside `Jinja for loops`_. It's used to
display a line after each post except the last one, to visually separate
them.
.. _Jinja for loops: https://jinja.palletsprojects.com/templates/#for
Create
------
The ``create`` view works the same as the auth ``register`` view. Either
the form is displayed, or the posted data is validated and the post is
added to the database or an error is shown.
The ``login_required`` decorator you wrote earlier is used on the blog
views. A user must be logged in to visit these views, otherwise they
will be redirected to the login page.
.. code-block:: python
:caption: ``flaskr/blog.py``
@bp.route('/create', methods=('GET', 'POST'))
@login_required
def create():
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None
if not title:
error = 'Title is required.'
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'INSERT INTO post (title, body, author_id)'
' VALUES (?, ?, ?)',
(title, body, g.user['id'])
)
db.commit()
return redirect(url_for('blog.index'))
return render_template('blog/create.html')
.. code-block:: html+jinja
:caption: ``flaskr/templates/blog/create.html``
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}New Post{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="title">Title</label>
<input name="title" id="title" value="{{ request.form['title'] }}" required>
<label for="body">Body</label>
<textarea name="body" id="body">{{ request.form['body'] }}</textarea>
<input type="submit" value="Save">
</form>
{% endblock %}
Update
------
Both the ``update`` and ``delete`` views will need to fetch a ``post``
by ``id`` and check if the author matches the logged in user. To avoid
duplicating code, you can write a function to get the ``post`` and call
it from each view.
.. code-block:: python
:caption: ``flaskr/blog.py``
def get_post(id, check_author=True):
post = get_db().execute(
'SELECT p.id, title, body, created, author_id, username'
' FROM post p JOIN user u ON p.author_id = u.id'
' WHERE p.id = ?',
(id,)
).fetchone()
if post is None:
abort(404, f"Post id {id} doesn't exist.")
if check_author and post['author_id'] != g.user['id']:
abort(403)
return post
:func:`abort` will raise a special exception that returns an HTTP status
code. It takes an optional message to show with the error, otherwise a
default message is used. ``404`` means "Not Found", and ``403`` means
"Forbidden". (``401`` means "Unauthorized", but you redirect to the
login page instead of returning that status.)
The ``check_author`` argument is defined so that the function can be
used to get a ``post`` without checking the author. This would be useful
if you wrote a view to show an individual post on a page, where the user
doesn't matter because they're not modifying the post.
.. code-block:: python
:caption: ``flaskr/blog.py``
@bp.route('/<int:id>/update', methods=('GET', 'POST'))
@login_required
def update(id):
post = get_post(id)
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None
if not title:
error = 'Title is required.'
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'UPDATE post SET title = ?, body = ?'
' WHERE id = ?',
(title, body, id)
)
db.commit()
return redirect(url_for('blog.index'))
return render_template('blog/update.html', post=post)
Unlike the views you've written so far, the ``update`` function takes
an argument, ``id``. That corresponds to the ``<int:id>`` in the route.
A real URL will look like ``/1/update``. Flask will capture the ``1``,
ensure it's an :class:`int`, and pass it as the ``id`` argument. If you
don't specify ``int:`` and instead do ``<id>``, it will be a string.
To generate a URL to the update page, :func:`url_for` needs to be passed
the ``id`` so it knows what to fill in:
``url_for('blog.update', id=post['id'])``. This is also in the
``index.html`` file above.
The ``create`` and ``update`` views look very similar. The main
difference is that the ``update`` view uses a ``post`` object and an
``UPDATE`` query instead of an ``INSERT``. With some clever refactoring,
you could use one view and template for both actions, but for the
tutorial it's clearer to keep them separate.
.. code-block:: html+jinja
:caption: ``flaskr/templates/blog/update.html``
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Edit "{{ post['title'] }}"{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="title">Title</label>
<input name="title" id="title"
value="{{ request.form['title'] or post['title'] }}" required>
<label for="body">Body</label>
<textarea name="body" id="body">{{ request.form['body'] or post['body'] }}</textarea>
<input type="submit" value="Save">
</form>
<hr>
<form action="{{ url_for('blog.delete', id=post['id']) }}" method="post">
<input class="danger" type="submit" value="Delete" onclick="return confirm('Are you sure?');">
</form>
{% endblock %}
This template has two forms. The first posts the edited data to the
current page (``/<id>/update``). The other form contains only a button
and specifies an ``action`` attribute that posts to the delete view
instead. The button uses some JavaScript to show a confirmation dialog
before submitting.
The pattern ``{{ request.form['title'] or post['title'] }}`` is used to
choose what data appears in the form. When the form hasn't been
submitted, the original ``post`` data appears, but if invalid form data
was posted you want to display that so the user can fix the error, so
``request.form`` is used instead. :data:`.request` is another variable
that's automatically available in templates.
Delete
------
The delete view doesn't have its own template, the delete button is part
of ``update.html`` and posts to the ``/<id>/delete`` URL. Since there
is no template, it will only handle the ``POST`` method and then redirect
to the ``index`` view.
.. code-block:: python
:caption: ``flaskr/blog.py``
@bp.route('/<int:id>/delete', methods=('POST',))
@login_required
def delete(id):
get_post(id)
db = get_db()
db.execute('DELETE FROM post WHERE id = ?', (id,))
db.commit()
return redirect(url_for('blog.index'))
Congratulations, you've now finished writing your application! Take some
time to try out everything in the browser. However, there's still more
to do before the project is complete.
Continue to :doc:`install`.

@ -0,0 +1,219 @@
.. currentmodule:: flask
Define and Access the Database
==============================
The application will use a `SQLite`_ database to store users and posts.
Python comes with built-in support for SQLite in the :mod:`sqlite3`
module.
SQLite is convenient because it doesn't require setting up a separate
database server and is built-in to Python. However, if concurrent
requests try to write to the database at the same time, they will slow
down as each write happens sequentially. Small applications won't notice
this. Once you become big, you may want to switch to a different
database.
The tutorial doesn't go into detail about SQL. If you are not familiar
with it, the SQLite docs describe the `language`_.
.. _SQLite: https://sqlite.org/about.html
.. _language: https://sqlite.org/lang.html
Connect to the Database
-----------------------
The first thing to do when working with a SQLite database (and most
other Python database libraries) is to create a connection to it. Any
queries and operations are performed using the connection, which is
closed after the work is finished.
In web applications this connection is typically tied to the request. It
is created at some point when handling a request, and closed before the
response is sent.
.. code-block:: python
:caption: ``flaskr/db.py``
import sqlite3
from datetime import datetime
import click
from flask import current_app, g
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
:data:`.g` is a special object that is unique for each request. It is
used to store data that might be accessed by multiple functions during
the request. The connection is stored and reused instead of creating a
new connection if ``get_db`` is called a second time in the same
request.
:data:`.current_app` is another special object that points to the Flask
application handling the request. Since you used an application factory,
there is no application object when writing the rest of your code.
``get_db`` will be called when the application has been created and is
handling a request, so :data:`.current_app` can be used.
:func:`sqlite3.connect` establishes a connection to the file pointed at
by the ``DATABASE`` configuration key. This file doesn't have to exist
yet, and won't until you initialize the database later.
:class:`sqlite3.Row` tells the connection to return rows that behave
like dicts. This allows accessing the columns by name.
``close_db`` checks if a connection was created by checking if ``g.db``
was set. If the connection exists, it is closed. Further down you will
tell your application about the ``close_db`` function in the application
factory so that it is called after each request.
Create the Tables
-----------------
In SQLite, data is stored in *tables* and *columns*. These need to be
created before you can store and retrieve data. Flaskr will store users
in the ``user`` table, and posts in the ``post`` table. Create a file
with the SQL commands needed to create empty tables:
.. code-block:: sql
:caption: ``flaskr/schema.sql``
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
);
CREATE TABLE post (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
body TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES user (id)
);
Add the Python functions that will run these SQL commands to the
``db.py`` file:
.. code-block:: python
:caption: ``flaskr/db.py``
def init_db():
db = get_db()
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
@click.command('init-db')
def init_db_command():
"""Clear the existing data and create new tables."""
init_db()
click.echo('Initialized the database.')
sqlite3.register_converter(
"timestamp", lambda v: datetime.fromisoformat(v.decode())
)
:meth:`open_resource() <Flask.open_resource>` opens a file relative to
the ``flaskr`` package, which is useful since you won't necessarily know
where that location is when deploying the application later. ``get_db``
returns a database connection, which is used to execute the commands
read from the file.
:func:`click.command` defines a command line command called ``init-db``
that calls the ``init_db`` function and shows a success message to the
user. You can read :doc:`/cli` to learn more about writing commands.
The call to :func:`sqlite3.register_converter` tells Python how to
interpret timestamp values in the database. We convert the value to a
:class:`datetime.datetime`.
Register with the Application
-----------------------------
The ``close_db`` and ``init_db_command`` functions need to be registered
with the application instance; otherwise, they won't be used by the
application. However, since you're using a factory function, that
instance isn't available when writing the functions. Instead, write a
function that takes an application and does the registration.
.. code-block:: python
:caption: ``flaskr/db.py``
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
:meth:`app.teardown_appcontext() <Flask.teardown_appcontext>` tells
Flask to call that function when cleaning up after returning the
response.
:meth:`app.cli.add_command() <click.Group.add_command>` adds a new
command that can be called with the ``flask`` command.
Import and call this function from the factory. Place the new code at
the end of the factory function before returning the app.
.. code-block:: python
:caption: ``flaskr/__init__.py``
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
Initialize the Database File
----------------------------
Now that ``init-db`` has been registered with the app, it can be called
using the ``flask`` command, similar to the ``run`` command from the
previous page.
.. note::
If you're still running the server from the previous page, you can
either stop the server, or run this command in a new terminal. If
you use a new terminal, remember to change to your project directory
and activate the env as described in :doc:`/installation`.
Run the ``init-db`` command:
.. code-block:: none
$ flask --app flaskr init-db
Initialized the database.
There will now be a ``flaskr.sqlite`` file in the ``instance`` folder in
your project.
Continue to :doc:`views`.

@ -0,0 +1,111 @@
Deploy to Production
====================
This part of the tutorial assumes you have a server that you want to
deploy your application to. It gives an overview of how to create the
distribution file and install it, but won't go into specifics about
what server or software to use. You can set up a new environment on your
development computer to try out the instructions below, but probably
shouldn't use it for hosting a real public application. See
:doc:`/deploying/index` for a list of many different ways to host your
application.
Build and Install
-----------------
When you want to deploy your application elsewhere, you build a *wheel*
(``.whl``) file. Install and use the ``build`` tool to do this.
.. code-block:: none
$ pip install build
$ python -m build --wheel
You can find the file in ``dist/flaskr-1.0.0-py3-none-any.whl``. The
file name is in the format of {project name}-{version}-{python tag}
-{abi tag}-{platform tag}.
Copy this file to another machine,
:ref:`set up a new virtualenv <install-create-env>`, then install the
file with ``pip``.
.. code-block:: none
$ pip install flaskr-1.0.0-py3-none-any.whl
Pip will install your project along with its dependencies.
Since this is a different machine, you need to run ``init-db`` again to
create the database in the instance folder.
.. code-block:: text
$ flask --app flaskr init-db
When Flask detects that it's installed (not in editable mode), it uses
a different directory for the instance folder. You can find it at
``.venv/var/flaskr-instance`` instead.
Configure the Secret Key
------------------------
In the beginning of the tutorial that you gave a default value for
:data:`SECRET_KEY`. This should be changed to some random bytes in
production. Otherwise, attackers could use the public ``'dev'`` key to
modify the session cookie, or anything else that uses the secret key.
You can use the following command to output a random secret key:
.. code-block:: none
$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
Create the ``config.py`` file in the instance folder, which the factory
will read from if it exists. Copy the generated value into it.
.. code-block:: python
:caption: ``.venv/var/flaskr-instance/config.py``
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
You can also set any other necessary configuration here, although
``SECRET_KEY`` is the only one needed for Flaskr.
Run with a Production Server
----------------------------
When running publicly rather than in development, you should not use the
built-in development server (``flask run``). The development server is
provided by Werkzeug for convenience, but is not designed to be
particularly efficient, stable, or secure.
Instead, use a production WSGI server. For example, to use `Waitress`_,
first install it in the virtual environment:
.. code-block:: none
$ pip install waitress
You need to tell Waitress about your application, but it doesn't use
``--app`` like ``flask run`` does. You need to tell it to import and
call the application factory to get an application object.
.. code-block:: none
$ waitress-serve --call 'flaskr:create_app'
Serving on http://0.0.0.0:8080
See :doc:`/deploying/index` for a list of many different ways to host
your application. Waitress is just an example, chosen for the tutorial
because it supports both Windows and Linux. There are many more WSGI
servers and deployment options that you may choose for your project.
.. _Waitress: https://docs.pylonsproject.org/projects/waitress/en/stable/
Continue to :doc:`next`.

@ -0,0 +1,162 @@
.. currentmodule:: flask
Application Setup
=================
A Flask application is an instance of the :class:`Flask` class.
Everything about the application, such as configuration and URLs, will
be registered with this class.
The most straightforward way to create a Flask application is to create
a global :class:`Flask` instance directly at the top of your code, like
how the "Hello, World!" example did on the previous page. While this is
simple and useful in some cases, it can cause some tricky issues as the
project grows.
Instead of creating a :class:`Flask` instance globally, you will create
it inside a function. This function is known as the *application
factory*. Any configuration, registration, and other setup the
application needs will happen inside the function, then the application
will be returned.
The Application Factory
-----------------------
It's time to start coding! Create the ``flaskr`` directory and add the
``__init__.py`` file. The ``__init__.py`` serves double duty: it will
contain the application factory, and it tells Python that the ``flaskr``
directory should be treated as a package.
.. code-block:: none
$ mkdir flaskr
.. code-block:: python
:caption: ``flaskr/__init__.py``
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
@app.route('/hello')
def hello():
return 'Hello, World!'
return app
``create_app`` is the application factory function. You'll add to it
later in the tutorial, but it already does a lot.
#. ``app = Flask(__name__, instance_relative_config=True)`` creates the
:class:`Flask` instance.
* ``__name__`` is the name of the current Python module. The app
needs to know where it's located to set up some paths, and
``__name__`` is a convenient way to tell it that.
* ``instance_relative_config=True`` tells the app that
configuration files are relative to the
:ref:`instance folder <instance-folders>`. The instance folder
is located outside the ``flaskr`` package and can hold local
data that shouldn't be committed to version control, such as
configuration secrets and the database file.
#. :meth:`app.config.from_mapping() <Config.from_mapping>` sets
some default configuration that the app will use:
* :data:`SECRET_KEY` is used by Flask and extensions to keep data
safe. It's set to ``'dev'`` to provide a convenient value
during development, but it should be overridden with a random
value when deploying.
* ``DATABASE`` is the path where the SQLite database file will be
saved. It's under
:attr:`app.instance_path <Flask.instance_path>`, which is the
path that Flask has chosen for the instance folder. You'll learn
more about the database in the next section.
#. :meth:`app.config.from_pyfile() <Config.from_pyfile>` overrides
the default configuration with values taken from the ``config.py``
file in the instance folder if it exists. For example, when
deploying, this can be used to set a real ``SECRET_KEY``.
* ``test_config`` can also be passed to the factory, and will be
used instead of the instance configuration. This is so the tests
you'll write later in the tutorial can be configured
independently of any development values you have configured.
#. :func:`os.makedirs` ensures that
:attr:`app.instance_path <Flask.instance_path>` exists. Flask
doesn't create the instance folder automatically, but it needs to be
created because your project will create the SQLite database file
there.
#. :meth:`@app.route() <Flask.route>` creates a simple route so you can
see the application working before getting into the rest of the
tutorial. It creates a connection between the URL ``/hello`` and a
function that returns a response, the string ``'Hello, World!'`` in
this case.
Run The Application
-------------------
Now you can run your application using the ``flask`` command. From the
terminal, tell Flask where to find your application, then run it in
debug mode. Remember, you should still be in the top-level
``flask-tutorial`` directory, not the ``flaskr`` package.
Debug mode shows an interactive debugger whenever a page raises an
exception, and restarts the server whenever you make changes to the
code. You can leave it running and just reload the browser page as you
follow the tutorial.
.. code-block:: text
$ flask --app flaskr run --debug
You'll see output similar to this:
.. code-block:: text
* Serving Flask app "flaskr"
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: nnn-nnn-nnn
Visit http://127.0.0.1:5000/hello in a browser and you should see the
"Hello, World!" message. Congratulations, you're now running your Flask
web application!
If another program is already using port 5000, you'll see
``OSError: [Errno 98]`` or ``OSError: [WinError 10013]`` when the
server tries to start. See :ref:`address-already-in-use` for how to
handle that.
Continue to :doc:`database`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@ -0,0 +1,64 @@
Tutorial
========
.. toctree::
:caption: Contents:
:maxdepth: 1
layout
factory
database
views
templates
static
blog
install
tests
deploy
next
This tutorial will walk you through creating a basic blog application
called Flaskr. Users will be able to register, log in, create posts,
and edit or delete their own posts. You will be able to package and
install the application on other computers.
.. image:: flaskr_index.png
:align: center
:class: screenshot
:alt: screenshot of index page
It's assumed that you're already familiar with Python. The `official
tutorial`_ in the Python docs is a great way to learn or review first.
.. _official tutorial: https://docs.python.org/3/tutorial/
While it's designed to give a good starting point, the tutorial doesn't
cover all of Flask's features. Check out the :doc:`/quickstart` for an
overview of what Flask can do, then dive into the docs to find out more.
The tutorial only uses what's provided by Flask and Python. In another
project, you might decide to use :doc:`/extensions` or other libraries
to make some tasks simpler.
.. image:: flaskr_login.png
:align: center
:class: screenshot
:alt: screenshot of login page
Flask is flexible. It doesn't require you to use any particular project
or code layout. However, when first starting, it's helpful to use a more
structured approach. This means that the tutorial will require a bit of
boilerplate up front, but it's done to avoid many common pitfalls that
new developers encounter, and it creates a project that's easy to expand
on. Once you become more comfortable with Flask, you can step out of
this structure and take full advantage of Flask's flexibility.
.. image:: flaskr_edit.png
:align: center
:class: screenshot
:alt: screenshot of edit page
:gh:`The tutorial project is available as an example in the Flask
repository <examples/tutorial>`, if you want to compare your project
with the final product as you follow the tutorial.
Continue to :doc:`layout`.

@ -0,0 +1,89 @@
Make the Project Installable
============================
Making your project installable means that you can build a *wheel* file and install that
in another environment, just like you installed Flask in your project's environment.
This makes deploying your project the same as installing any other library, so you're
using all the standard Python tools to manage everything.
Installing also comes with other benefits that might not be obvious from
the tutorial or as a new Python user, including:
* Currently, Python and Flask understand how to use the ``flaskr``
package only because you're running from your project's directory.
Installing means you can import it no matter where you run from.
* You can manage your project's dependencies just like other packages
do, so ``pip install yourproject.whl`` installs them.
* Test tools can isolate your test environment from your development
environment.
.. note::
This is being introduced late in the tutorial, but in your future
projects you should always start with this.
Describe the Project
--------------------
The ``pyproject.toml`` file describes your project and how to build it.
.. code-block:: toml
:caption: ``pyproject.toml``
[project]
name = "flaskr"
version = "1.0.0"
description = "The basic blog app built in the Flask tutorial."
dependencies = [
"flask",
]
[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"
See the official `Packaging tutorial <packaging tutorial_>`_ for more
explanation of the files and options used.
.. _packaging tutorial: https://packaging.python.org/tutorials/packaging-projects/
Install the Project
-------------------
Use ``pip`` to install your project in the virtual environment.
.. code-block:: none
$ pip install -e .
This tells pip to find ``pyproject.toml`` in the current directory and install the
project in *editable* or *development* mode. Editable mode means that as you make
changes to your local code, you'll only need to re-install if you change the metadata
about the project, such as its dependencies.
You can observe that the project is now installed with ``pip list``.
.. code-block:: none
$ pip list
Package Version Location
-------------- --------- ----------------------------------
click 6.7
Flask 1.0
flaskr 1.0.0 /home/user/Projects/flask-tutorial
itsdangerous 0.24
Jinja2 2.10
MarkupSafe 1.0
pip 9.0.3
Werkzeug 0.14.1
Nothing changes from how you've been running your project so far.
``--app`` is still set to ``flaskr`` and ``flask run`` still runs
the application, but you can call it from anywhere, not just the
``flask-tutorial`` directory.
Continue to :doc:`tests`.

@ -0,0 +1,110 @@
Project Layout
==============
Create a project directory and enter it:
.. code-block:: none
$ mkdir flask-tutorial
$ cd flask-tutorial
Then follow the :doc:`installation instructions </installation>` to set
up a Python virtual environment and install Flask for your project.
The tutorial will assume you're working from the ``flask-tutorial``
directory from now on. The file names at the top of each code block are
relative to this directory.
----
A Flask application can be as simple as a single file.
.. code-block:: python
:caption: ``hello.py``
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
However, as a project gets bigger, it becomes overwhelming to keep all
the code in one file. Python projects use *packages* to organize code
into multiple modules that can be imported where needed, and the
tutorial will do this as well.
The project directory will contain:
* ``flaskr/``, a Python package containing your application code and
files.
* ``tests/``, a directory containing test modules.
* ``.venv/``, a Python virtual environment where Flask and other
dependencies are installed.
* Installation files telling Python how to install your project.
* Version control config, such as `git`_. You should make a habit of
using some type of version control for all your projects, no matter
the size.
* Any other project files you might add in the future.
.. _git: https://git-scm.com/
By the end, your project layout will look like this:
.. code-block:: none
/home/user/Projects/flask-tutorial
├── flaskr/
│ ├── __init__.py
│ ├── db.py
│ ├── schema.sql
│ ├── auth.py
│ ├── blog.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── blog/
│ │ ├── create.html
│ │ ├── index.html
│ │ └── update.html
│ └── static/
│ └── style.css
├── tests/
│ ├── conftest.py
│ ├── data.sql
│ ├── test_factory.py
│ ├── test_db.py
│ ├── test_auth.py
│ └── test_blog.py
├── .venv/
├── pyproject.toml
└── MANIFEST.in
If you're using version control, the following files that are generated
while running your project should be ignored. There may be other files
based on the editor you use. In general, ignore files that you didn't
write. For example, with git:
.. code-block:: none
:caption: ``.gitignore``
.venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
Continue to :doc:`factory`.

@ -0,0 +1,38 @@
Keep Developing!
================
You've learned about quite a few Flask and Python concepts throughout
the tutorial. Go back and review the tutorial and compare your code with
the steps you took to get there. Compare your project to the
:gh:`example project <examples/tutorial>`, which might look a bit
different due to the step-by-step nature of the tutorial.
There's a lot more to Flask than what you've seen so far. Even so,
you're now equipped to start developing your own web applications. Check
out the :doc:`/quickstart` for an overview of what Flask can do, then
dive into the docs to keep learning. Flask uses `Jinja`_, `Click`_,
`Werkzeug`_, and `ItsDangerous`_ behind the scenes, and they all have
their own documentation too. You'll also be interested in
:doc:`/extensions` which make tasks like working with the database or
validating form data easier and more powerful.
If you want to keep developing your Flaskr project, here are some ideas
for what to try next:
* A detail view to show a single post. Click a post's title to go to
its page.
* Like / unlike a post.
* Comments.
* Tags. Clicking a tag shows all the posts with that tag.
* A search box that filters the index page by name.
* Paged display. Only show 5 posts per page.
* Upload an image to go along with a post.
* Format posts using Markdown.
* An RSS feed of new posts.
Have fun and make awesome applications!
.. _Jinja: https://palletsprojects.com/p/jinja/
.. _Click: https://palletsprojects.com/p/click/
.. _Werkzeug: https://palletsprojects.com/p/werkzeug/
.. _ItsDangerous: https://palletsprojects.com/p/itsdangerous/

@ -0,0 +1,72 @@
Static Files
============
The authentication views and templates work, but they look very plain
right now. Some `CSS`_ can be added to add style to the HTML layout you
constructed. The style won't change, so it's a *static* file rather than
a template.
Flask automatically adds a ``static`` view that takes a path relative
to the ``flaskr/static`` directory and serves it. The ``base.html``
template already has a link to the ``style.css`` file:
.. code-block:: html+jinja
{{ url_for('static', filename='style.css') }}
Besides CSS, other types of static files might be files with JavaScript
functions, or a logo image. They are all placed under the
``flaskr/static`` directory and referenced with
``url_for('static', filename='...')``.
This tutorial isn't focused on how to write CSS, so you can just copy
the following into the ``flaskr/static/style.css`` file:
.. code-block:: css
:caption: ``flaskr/static/style.css``
html { font-family: sans-serif; background: #eee; padding: 1rem; }
body { max-width: 960px; margin: 0 auto; background: white; }
h1 { font-family: serif; color: #377ba8; margin: 1rem 0; }
a { color: #377ba8; }
hr { border: none; border-top: 1px solid lightgray; }
nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; }
nav h1 { flex: auto; margin: 0; }
nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; }
nav ul { display: flex; list-style: none; margin: 0; padding: 0; }
nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; }
.content { padding: 0 1rem 1rem; }
.content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; }
.content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; }
.flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; }
.post > header { display: flex; align-items: flex-end; font-size: 0.85em; }
.post > header > div:first-of-type { flex: auto; }
.post > header h1 { font-size: 1.5em; margin-bottom: 0; }
.post .about { color: slategray; font-style: italic; }
.post .body { white-space: pre-line; }
.content:last-child { margin-bottom: 0; }
.content form { margin: 1em 0; display: flex; flex-direction: column; }
.content label { font-weight: bold; margin-bottom: 0.5em; }
.content input, .content textarea { margin-bottom: 1em; }
.content textarea { min-height: 12em; resize: vertical; }
input.danger { color: #cc2f2e; }
input[type=submit] { align-self: start; min-width: 10em; }
You can find a less compact version of ``style.css`` in the
:gh:`example code <examples/tutorial/flaskr/static/style.css>`.
Go to http://127.0.0.1:5000/auth/login and the page should look like the
screenshot below.
.. image:: flaskr_login.png
:align: center
:class: screenshot
:alt: screenshot of login page
You can read more about CSS from `Mozilla's documentation <CSS_>`_. If
you change a static file, refresh the browser page. If the change
doesn't show up, try clearing your browser's cache.
.. _CSS: https://developer.mozilla.org/docs/Web/CSS
Continue to :doc:`blog`.

@ -0,0 +1,187 @@
.. currentmodule:: flask
Templates
=========
You've written the authentication views for your application, but if
you're running the server and try to go to any of the URLs, you'll see a
``TemplateNotFound`` error. That's because the views are calling
:func:`render_template`, but you haven't written the templates yet.
The template files will be stored in the ``templates`` directory inside
the ``flaskr`` package.
Templates are files that contain static data as well as placeholders
for dynamic data. A template is rendered with specific data to produce a
final document. Flask uses the `Jinja`_ template library to render
templates.
In your application, you will use templates to render `HTML`_ which
will display in the user's browser. In Flask, Jinja is configured to
*autoescape* any data that is rendered in HTML templates. This means
that it's safe to render user input; any characters they've entered that
could mess with the HTML, such as ``<`` and ``>`` will be *escaped* with
*safe* values that look the same in the browser but don't cause unwanted
effects.
Jinja looks and behaves mostly like Python. Special delimiters are used
to distinguish Jinja syntax from the static data in the template.
Anything between ``{{`` and ``}}`` is an expression that will be output
to the final document. ``{%`` and ``%}`` denotes a control flow
statement like ``if`` and ``for``. Unlike Python, blocks are denoted
by start and end tags rather than indentation since static text within
a block could change indentation.
.. _Jinja: https://jinja.palletsprojects.com/templates/
.. _HTML: https://developer.mozilla.org/docs/Web/HTML
The Base Layout
---------------
Each page in the application will have the same basic layout around a
different body. Instead of writing the entire HTML structure in each
template, each template will *extend* a base template and override
specific sections.
.. code-block:: html+jinja
:caption: ``flaskr/templates/base.html``
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
<h1>Flaskr</h1>
<ul>
{% if g.user %}
<li><span>{{ g.user['username'] }}</span>
<li><a href="{{ url_for('auth.logout') }}">Log Out</a>
{% else %}
<li><a href="{{ url_for('auth.register') }}">Register</a>
<li><a href="{{ url_for('auth.login') }}">Log In</a>
{% endif %}
</ul>
</nav>
<section class="content">
<header>
{% block header %}{% endblock %}
</header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</section>
:data:`.g` is automatically available in templates. Based on if
``g.user`` is set (from ``load_logged_in_user``), either the username
and a log out link are displayed, or links to register and log in
are displayed. :func:`url_for` is also automatically available, and is
used to generate URLs to views instead of writing them out manually.
After the page title, and before the content, the template loops over
each message returned by :func:`get_flashed_messages`. You used
:func:`flash` in the views to show error messages, and this is the code
that will display them.
There are three blocks defined here that will be overridden in the other
templates:
#. ``{% block title %}`` will change the title displayed in the
browser's tab and window title.
#. ``{% block header %}`` is similar to ``title`` but will change the
title displayed on the page.
#. ``{% block content %}`` is where the content of each page goes, such
as the login form or a blog post.
The base template is directly in the ``templates`` directory. To keep
the others organized, the templates for a blueprint will be placed in a
directory with the same name as the blueprint.
Register
--------
.. code-block:: html+jinja
:caption: ``flaskr/templates/auth/register.html``
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="username">Username</label>
<input name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Register">
</form>
{% endblock %}
``{% extends 'base.html' %}`` tells Jinja that this template should
replace the blocks from the base template. All the rendered content must
appear inside ``{% block %}`` tags that override blocks from the base
template.
A useful pattern used here is to place ``{% block title %}`` inside
``{% block header %}``. This will set the title block and then output
the value of it into the header block, so that both the window and page
share the same title without writing it twice.
The ``input`` tags are using the ``required`` attribute here. This tells
the browser not to submit the form until those fields are filled in. If
the user is using an older browser that doesn't support that attribute,
or if they are using something besides a browser to make requests, you
still want to validate the data in the Flask view. It's important to
always fully validate the data on the server, even if the client does
some validation as well.
Log In
------
This is identical to the register template except for the title and
submit button.
.. code-block:: html+jinja
:caption: ``flaskr/templates/auth/login.html``
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Log In{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="username">Username</label>
<input name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Log In">
</form>
{% endblock %}
Register A User
---------------
Now that the authentication templates are written, you can register a
user. Make sure the server is still running (``flask run`` if it's not),
then go to http://127.0.0.1:5000/auth/register.
Try clicking the "Register" button without filling out the form and see
that the browser shows an error message. Try removing the ``required``
attributes from the ``register.html`` template and click "Register"
again. Instead of the browser showing an error, the page will reload and
the error from :func:`flash` in the view will be shown.
Fill out a username and password and you'll be redirected to the login
page. Try entering an incorrect username, or the correct username and
incorrect password. If you log in you'll get an error because there's
no ``index`` view to redirect to yet.
Continue to :doc:`static`.

@ -0,0 +1,559 @@
.. currentmodule:: flask
Test Coverage
=============
Writing unit tests for your application lets you check that the code
you wrote works the way you expect. Flask provides a test client that
simulates requests to the application and returns the response data.
You should test as much of your code as possible. Code in functions only
runs when the function is called, and code in branches, such as ``if``
blocks, only runs when the condition is met. You want to make sure that
each function is tested with data that covers each branch.
The closer you get to 100% coverage, the more comfortable you can be
that making a change won't unexpectedly change other behavior. However,
100% coverage doesn't guarantee that your application doesn't have bugs.
In particular, it doesn't test how the user interacts with the
application in the browser. Despite this, test coverage is an important
tool to use during development.
.. note::
This is being introduced late in the tutorial, but in your future
projects you should test as you develop.
You'll use `pytest`_ and `coverage`_ to test and measure your code.
Install them both:
.. code-block:: none
$ pip install pytest coverage
.. _pytest: https://pytest.readthedocs.io/
.. _coverage: https://coverage.readthedocs.io/
Setup and Fixtures
------------------
The test code is located in the ``tests`` directory. This directory is
*next to* the ``flaskr`` package, not inside it. The
``tests/conftest.py`` file contains setup functions called *fixtures*
that each test will use. Tests are in Python modules that start with
``test_``, and each test function in those modules also starts with
``test_``.
Each test will create a new temporary database file and populate some
data that will be used in the tests. Write a SQL file to insert that
data.
.. code-block:: sql
:caption: ``tests/data.sql``
INSERT INTO user (username, password)
VALUES
('test', 'pbkdf2:sha256:50000$TCI4GzcX$0de171a4f4dac32e3364c7ddc7c14f3e2fa61f2d17574483f7ffbb431b4acb2f'),
('other', 'pbkdf2:sha256:50000$kJPKsz6N$d2d4784f1b030a9761f5ccaeeaca413f27f2ecb76d6168407af962ddce849f79');
INSERT INTO post (title, body, author_id, created)
VALUES
('test title', 'test' || x'0a' || 'body', 1, '2018-01-01 00:00:00');
The ``app`` fixture will call the factory and pass ``test_config`` to
configure the application and database for testing instead of using your
local development configuration.
.. code-block:: python
:caption: ``tests/conftest.py``
import os
import tempfile
import pytest
from flaskr import create_app
from flaskr.db import get_db, init_db
with open(os.path.join(os.path.dirname(__file__), 'data.sql'), 'rb') as f:
_data_sql = f.read().decode('utf8')
@pytest.fixture
def app():
db_fd, db_path = tempfile.mkstemp()
app = create_app({
'TESTING': True,
'DATABASE': db_path,
})
with app.app_context():
init_db()
get_db().executescript(_data_sql)
yield app
os.close(db_fd)
os.unlink(db_path)
@pytest.fixture
def client(app):
return app.test_client()
@pytest.fixture
def runner(app):
return app.test_cli_runner()
:func:`tempfile.mkstemp` creates and opens a temporary file, returning
the file descriptor and the path to it. The ``DATABASE`` path is
overridden so it points to this temporary path instead of the instance
folder. After setting the path, the database tables are created and the
test data is inserted. After the test is over, the temporary file is
closed and removed.
:data:`TESTING` tells Flask that the app is in test mode. Flask changes
some internal behavior so it's easier to test, and other extensions can
also use the flag to make testing them easier.
The ``client`` fixture calls
:meth:`app.test_client() <Flask.test_client>` with the application
object created by the ``app`` fixture. Tests will use the client to make
requests to the application without running the server.
The ``runner`` fixture is similar to ``client``.
:meth:`app.test_cli_runner() <Flask.test_cli_runner>` creates a runner
that can call the Click commands registered with the application.
Pytest uses fixtures by matching their function names with the names
of arguments in the test functions. For example, the ``test_hello``
function you'll write next takes a ``client`` argument. Pytest matches
that with the ``client`` fixture function, calls it, and passes the
returned value to the test function.
Factory
-------
There's not much to test about the factory itself. Most of the code will
be executed for each test already, so if something fails the other tests
will notice.
The only behavior that can change is passing test config. If config is
not passed, there should be some default configuration, otherwise the
configuration should be overridden.
.. code-block:: python
:caption: ``tests/test_factory.py``
from flaskr import create_app
def test_config():
assert not create_app().testing
assert create_app({'TESTING': True}).testing
def test_hello(client):
response = client.get('/hello')
assert response.data == b'Hello, World!'
You added the ``hello`` route as an example when writing the factory at
the beginning of the tutorial. It returns "Hello, World!", so the test
checks that the response data matches.
Database
--------
Within an application context, ``get_db`` should return the same
connection each time it's called. After the context, the connection
should be closed.
.. code-block:: python
:caption: ``tests/test_db.py``
import sqlite3
import pytest
from flaskr.db import get_db
def test_get_close_db(app):
with app.app_context():
db = get_db()
assert db is get_db()
with pytest.raises(sqlite3.ProgrammingError) as e:
db.execute('SELECT 1')
assert 'closed' in str(e.value)
The ``init-db`` command should call the ``init_db`` function and output
a message.
.. code-block:: python
:caption: ``tests/test_db.py``
def test_init_db_command(runner, monkeypatch):
class Recorder(object):
called = False
def fake_init_db():
Recorder.called = True
monkeypatch.setattr('flaskr.db.init_db', fake_init_db)
result = runner.invoke(args=['init-db'])
assert 'Initialized' in result.output
assert Recorder.called
This test uses Pytest's ``monkeypatch`` fixture to replace the
``init_db`` function with one that records that it's been called. The
``runner`` fixture you wrote above is used to call the ``init-db``
command by name.
Authentication
--------------
For most of the views, a user needs to be logged in. The easiest way to
do this in tests is to make a ``POST`` request to the ``login`` view
with the client. Rather than writing that out every time, you can write
a class with methods to do that, and use a fixture to pass it the client
for each test.
.. code-block:: python
:caption: ``tests/conftest.py``
class AuthActions(object):
def __init__(self, client):
self._client = client
def login(self, username='test', password='test'):
return self._client.post(
'/auth/login',
data={'username': username, 'password': password}
)
def logout(self):
return self._client.get('/auth/logout')
@pytest.fixture
def auth(client):
return AuthActions(client)
With the ``auth`` fixture, you can call ``auth.login()`` in a test to
log in as the ``test`` user, which was inserted as part of the test
data in the ``app`` fixture.
The ``register`` view should render successfully on ``GET``. On ``POST``
with valid form data, it should redirect to the login URL and the user's
data should be in the database. Invalid data should display error
messages.
.. code-block:: python
:caption: ``tests/test_auth.py``
import pytest
from flask import g, session
from flaskr.db import get_db
def test_register(client, app):
assert client.get('/auth/register').status_code == 200
response = client.post(
'/auth/register', data={'username': 'a', 'password': 'a'}
)
assert response.headers["Location"] == "/auth/login"
with app.app_context():
assert get_db().execute(
"SELECT * FROM user WHERE username = 'a'",
).fetchone() is not None
@pytest.mark.parametrize(('username', 'password', 'message'), (
('', '', b'Username is required.'),
('a', '', b'Password is required.'),
('test', 'test', b'already registered'),
))
def test_register_validate_input(client, username, password, message):
response = client.post(
'/auth/register',
data={'username': username, 'password': password}
)
assert message in response.data
:meth:`client.get() <werkzeug.test.Client.get>` makes a ``GET`` request
and returns the :class:`Response` object returned by Flask. Similarly,
:meth:`client.post() <werkzeug.test.Client.post>` makes a ``POST``
request, converting the ``data`` dict into form data.
To test that the page renders successfully, a simple request is made and
checked for a ``200 OK`` :attr:`~Response.status_code`. If
rendering failed, Flask would return a ``500 Internal Server Error``
code.
:attr:`~Response.headers` will have a ``Location`` header with the login
URL when the register view redirects to the login view.
:attr:`~Response.data` contains the body of the response as bytes. If
you expect a certain value to render on the page, check that it's in
``data``. Bytes must be compared to bytes. If you want to compare text,
use :meth:`get_data(as_text=True) <werkzeug.wrappers.Response.get_data>`
instead.
``pytest.mark.parametrize`` tells Pytest to run the same test function
with different arguments. You use it here to test different invalid
input and error messages without writing the same code three times.
The tests for the ``login`` view are very similar to those for
``register``. Rather than testing the data in the database,
:data:`.session` should have ``user_id`` set after logging in.
.. code-block:: python
:caption: ``tests/test_auth.py``
def test_login(client, auth):
assert client.get('/auth/login').status_code == 200
response = auth.login()
assert response.headers["Location"] == "/"
with client:
client.get('/')
assert session['user_id'] == 1
assert g.user['username'] == 'test'
@pytest.mark.parametrize(('username', 'password', 'message'), (
('a', 'test', b'Incorrect username.'),
('test', 'a', b'Incorrect password.'),
))
def test_login_validate_input(auth, username, password, message):
response = auth.login(username, password)
assert message in response.data
Using ``client`` in a ``with`` block allows accessing context variables
such as :data:`.session` after the response is returned. Normally,
accessing ``session`` outside of a request would raise an error.
Testing ``logout`` is the opposite of ``login``. :data:`.session` should
not contain ``user_id`` after logging out.
.. code-block:: python
:caption: ``tests/test_auth.py``
def test_logout(client, auth):
auth.login()
with client:
auth.logout()
assert 'user_id' not in session
Blog
----
All the blog views use the ``auth`` fixture you wrote earlier. Call
``auth.login()`` and subsequent requests from the client will be logged
in as the ``test`` user.
The ``index`` view should display information about the post that was
added with the test data. When logged in as the author, there should be
a link to edit the post.
You can also test some more authentication behavior while testing the
``index`` view. When not logged in, each page shows links to log in or
register. When logged in, there's a link to log out.
.. code-block:: python
:caption: ``tests/test_blog.py``
import pytest
from flaskr.db import get_db
def test_index(client, auth):
response = client.get('/')
assert b"Log In" in response.data
assert b"Register" in response.data
auth.login()
response = client.get('/')
assert b'Log Out' in response.data
assert b'test title' in response.data
assert b'by test on 2018-01-01' in response.data
assert b'test\nbody' in response.data
assert b'href="/1/update"' in response.data
A user must be logged in to access the ``create``, ``update``, and
``delete`` views. The logged in user must be the author of the post to
access ``update`` and ``delete``, otherwise a ``403 Forbidden`` status
is returned. If a ``post`` with the given ``id`` doesn't exist,
``update`` and ``delete`` should return ``404 Not Found``.
.. code-block:: python
:caption: ``tests/test_blog.py``
@pytest.mark.parametrize('path', (
'/create',
'/1/update',
'/1/delete',
))
def test_login_required(client, path):
response = client.post(path)
assert response.headers["Location"] == "/auth/login"
def test_author_required(app, client, auth):
# change the post author to another user
with app.app_context():
db = get_db()
db.execute('UPDATE post SET author_id = 2 WHERE id = 1')
db.commit()
auth.login()
# current user can't modify other user's post
assert client.post('/1/update').status_code == 403
assert client.post('/1/delete').status_code == 403
# current user doesn't see edit link
assert b'href="/1/update"' not in client.get('/').data
@pytest.mark.parametrize('path', (
'/2/update',
'/2/delete',
))
def test_exists_required(client, auth, path):
auth.login()
assert client.post(path).status_code == 404
The ``create`` and ``update`` views should render and return a
``200 OK`` status for a ``GET`` request. When valid data is sent in a
``POST`` request, ``create`` should insert the new post data into the
database, and ``update`` should modify the existing data. Both pages
should show an error message on invalid data.
.. code-block:: python
:caption: ``tests/test_blog.py``
def test_create(client, auth, app):
auth.login()
assert client.get('/create').status_code == 200
client.post('/create', data={'title': 'created', 'body': ''})
with app.app_context():
db = get_db()
count = db.execute('SELECT COUNT(id) FROM post').fetchone()[0]
assert count == 2
def test_update(client, auth, app):
auth.login()
assert client.get('/1/update').status_code == 200
client.post('/1/update', data={'title': 'updated', 'body': ''})
with app.app_context():
db = get_db()
post = db.execute('SELECT * FROM post WHERE id = 1').fetchone()
assert post['title'] == 'updated'
@pytest.mark.parametrize('path', (
'/create',
'/1/update',
))
def test_create_update_validate(client, auth, path):
auth.login()
response = client.post(path, data={'title': '', 'body': ''})
assert b'Title is required.' in response.data
The ``delete`` view should redirect to the index URL and the post should
no longer exist in the database.
.. code-block:: python
:caption: ``tests/test_blog.py``
def test_delete(client, auth, app):
auth.login()
response = client.post('/1/delete')
assert response.headers["Location"] == "/"
with app.app_context():
db = get_db()
post = db.execute('SELECT * FROM post WHERE id = 1').fetchone()
assert post is None
Running the Tests
-----------------
Some extra configuration, which is not required but makes running tests with coverage
less verbose, can be added to the project's ``pyproject.toml`` file.
.. code-block:: toml
:caption: ``pyproject.toml``
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.coverage.run]
branch = true
source = ["flaskr"]
To run the tests, use the ``pytest`` command. It will find and run all
the test functions you've written.
.. code-block:: none
$ pytest
========================= test session starts ==========================
platform linux -- Python 3.6.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
rootdir: /home/user/Projects/flask-tutorial
collected 23 items
tests/test_auth.py ........ [ 34%]
tests/test_blog.py ............ [ 86%]
tests/test_db.py .. [ 95%]
tests/test_factory.py .. [100%]
====================== 24 passed in 0.64 seconds =======================
If any tests fail, pytest will show the error that was raised. You can
run ``pytest -v`` to get a list of each test function rather than dots.
To measure the code coverage of your tests, use the ``coverage`` command
to run pytest instead of running it directly.
.. code-block:: none
$ coverage run -m pytest
You can either view a simple coverage report in the terminal:
.. code-block:: none
$ coverage report
Name Stmts Miss Branch BrPart Cover
------------------------------------------------------
flaskr/__init__.py 21 0 2 0 100%
flaskr/auth.py 54 0 22 0 100%
flaskr/blog.py 54 0 16 0 100%
flaskr/db.py 24 0 4 0 100%
------------------------------------------------------
TOTAL 153 0 44 0 100%
An HTML report allows you to see which lines were covered in each file:
.. code-block:: none
$ coverage html
This generates files in the ``htmlcov`` directory. Open
``htmlcov/index.html`` in your browser to see the report.
Continue to :doc:`deploy`.

@ -0,0 +1,305 @@
.. currentmodule:: flask
Blueprints and Views
====================
A view function is the code you write to respond to requests to your
application. Flask uses patterns to match the incoming request URL to
the view that should handle it. The view returns data that Flask turns
into an outgoing response. Flask can also go the other direction and
generate a URL to a view based on its name and arguments.
Create a Blueprint
------------------
A :class:`Blueprint` is a way to organize a group of related views and
other code. Rather than registering views and other code directly with
an application, they are registered with a blueprint. Then the blueprint
is registered with the application when it is available in the factory
function.
Flaskr will have two blueprints, one for authentication functions and
one for the blog posts functions. The code for each blueprint will go
in a separate module. Since the blog needs to know about authentication,
you'll write the authentication one first.
.. code-block:: python
:caption: ``flaskr/auth.py``
import functools
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash
from flaskr.db import get_db
bp = Blueprint('auth', __name__, url_prefix='/auth')
This creates a :class:`Blueprint` named ``'auth'``. Like the application
object, the blueprint needs to know where it's defined, so ``__name__``
is passed as the second argument. The ``url_prefix`` will be prepended
to all the URLs associated with the blueprint.
Import and register the blueprint from the factory using
:meth:`app.register_blueprint() <Flask.register_blueprint>`. Place the
new code at the end of the factory function before returning the app.
.. code-block:: python
:caption: ``flaskr/__init__.py``
def create_app():
app = ...
# existing code omitted
from . import auth
app.register_blueprint(auth.bp)
return app
The authentication blueprint will have views to register new users and
to log in and log out.
The First View: Register
------------------------
When the user visits the ``/auth/register`` URL, the ``register`` view
will return `HTML`_ with a form for them to fill out. When they submit
the form, it will validate their input and either show the form again
with an error message or create the new user and go to the login page.
.. _HTML: https://developer.mozilla.org/docs/Web/HTML
For now you will just write the view code. On the next page, you'll
write templates to generate the HTML form.
.. code-block:: python
:caption: ``flaskr/auth.py``
@bp.route('/register', methods=('GET', 'POST'))
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
if not username:
error = 'Username is required.'
elif not password:
error = 'Password is required.'
if error is None:
try:
db.execute(
"INSERT INTO user (username, password) VALUES (?, ?)",
(username, generate_password_hash(password)),
)
db.commit()
except db.IntegrityError:
error = f"User {username} is already registered."
else:
return redirect(url_for("auth.login"))
flash(error)
return render_template('auth/register.html')
Here's what the ``register`` view function is doing:
#. :meth:`@bp.route <Blueprint.route>` associates the URL ``/register``
with the ``register`` view function. When Flask receives a request
to ``/auth/register``, it will call the ``register`` view and use
the return value as the response.
#. If the user submitted the form,
:attr:`request.method <Request.method>` will be ``'POST'``. In this
case, start validating the input.
#. :attr:`request.form <Request.form>` is a special type of
:class:`dict` mapping submitted form keys and values. The user will
input their ``username`` and ``password``.
#. Validate that ``username`` and ``password`` are not empty.
#. If validation succeeds, insert the new user data into the database.
- :meth:`db.execute <sqlite3.Connection.execute>` takes a SQL
query with ``?`` placeholders for any user input, and a tuple of
values to replace the placeholders with. The database library
will take care of escaping the values so you are not vulnerable
to a *SQL injection attack*.
- For security, passwords should never be stored in the database
directly. Instead,
:func:`~werkzeug.security.generate_password_hash` is used to
securely hash the password, and that hash is stored. Since this
query modifies data,
:meth:`db.commit() <sqlite3.Connection.commit>` needs to be
called afterwards to save the changes.
- An :exc:`sqlite3.IntegrityError` will occur if the username
already exists, which should be shown to the user as another
validation error.
#. After storing the user, they are redirected to the login page.
:func:`url_for` generates the URL for the login view based on its
name. This is preferable to writing the URL directly as it allows
you to change the URL later without changing all code that links to
it. :func:`redirect` generates a redirect response to the generated
URL.
#. If validation fails, the error is shown to the user. :func:`flash`
stores messages that can be retrieved when rendering the template.
#. When the user initially navigates to ``auth/register``, or
there was a validation error, an HTML page with the registration
form should be shown. :func:`render_template` will render a template
containing the HTML, which you'll write in the next step of the
tutorial.
Login
-----
This view follows the same pattern as the ``register`` view above.
.. code-block:: python
:caption: ``flaskr/auth.py``
@bp.route('/login', methods=('GET', 'POST'))
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
user = db.execute(
'SELECT * FROM user WHERE username = ?', (username,)
).fetchone()
if user is None:
error = 'Incorrect username.'
elif not check_password_hash(user['password'], password):
error = 'Incorrect password.'
if error is None:
session.clear()
session['user_id'] = user['id']
return redirect(url_for('index'))
flash(error)
return render_template('auth/login.html')
There are a few differences from the ``register`` view:
#. The user is queried first and stored in a variable for later use.
:meth:`~sqlite3.Cursor.fetchone` returns one row from the query.
If the query returned no results, it returns ``None``. Later,
:meth:`~sqlite3.Cursor.fetchall` will be used, which returns a list
of all results.
#. :func:`~werkzeug.security.check_password_hash` hashes the submitted
password in the same way as the stored hash and securely compares
them. If they match, the password is valid.
#. :data:`.session` is a :class:`dict` that stores data across requests.
When validation succeeds, the user's ``id`` is stored in a new
session. The data is stored in a *cookie* that is sent to the
browser, and the browser then sends it back with subsequent requests.
Flask securely *signs* the data so that it can't be tampered with.
Now that the user's ``id`` is stored in the :data:`.session`, it will be
available on subsequent requests. At the beginning of each request, if
a user is logged in their information should be loaded and made
available to other views.
.. code-block:: python
:caption: ``flaskr/auth.py``
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
:meth:`bp.before_app_request() <Blueprint.before_app_request>` registers
a function that runs before the view function, no matter what URL is
requested. ``load_logged_in_user`` checks if a user id is stored in the
:data:`.session` and gets that user's data from the database, storing it
on :data:`g.user <g>`, which lasts for the length of the request. If
there is no user id, or if the id doesn't exist, ``g.user`` will be
``None``.
Logout
------
To log out, you need to remove the user id from the :data:`.session`.
Then ``load_logged_in_user`` won't load a user on subsequent requests.
.. code-block:: python
:caption: ``flaskr/auth.py``
@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
Require Authentication in Other Views
-------------------------------------
Creating, editing, and deleting blog posts will require a user to be
logged in. A *decorator* can be used to check this for each view it's
applied to.
.. code-block:: python
:caption: ``flaskr/auth.py``
def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))
return view(**kwargs)
return wrapped_view
This decorator returns a new view function that wraps the original view
it's applied to. The new function checks if a user is loaded and
redirects to the login page otherwise. If a user is loaded the original
view is called and continues normally. You'll use this decorator when
writing the blog views.
Endpoints and URLs
------------------
The :func:`url_for` function generates the URL to a view based on a name
and arguments. The name associated with a view is also called the
*endpoint*, and by default it's the same as the name of the view
function.
For example, the ``hello()`` view that was added to the app
factory earlier in the tutorial has the name ``'hello'`` and can be
linked to with ``url_for('hello')``. If it took an argument, which
you'll see later, it would be linked to using
``url_for('hello', who='World')``.
When using a blueprint, the name of the blueprint is prepended to the
name of the function, so the endpoint for the ``login`` function you
wrote above is ``'auth.login'`` because you added it to the ``'auth'``
blueprint.
Continue to :doc:`templates`.

@ -0,0 +1,324 @@
Class-based Views
=================
.. currentmodule:: flask.views
This page introduces using the :class:`View` and :class:`MethodView`
classes to write class-based views.
A class-based view is a class that acts as a view function. Because it
is a class, different instances of the class can be created with
different arguments, to change the behavior of the view. This is also
known as generic, reusable, or pluggable views.
An example of where this is useful is defining a class that creates an
API based on the database model it is initialized with.
For more complex API behavior and customization, look into the various
API extensions for Flask.
Basic Reusable View
-------------------
Let's walk through an example converting a view function to a view
class. We start with a view function that queries a list of users then
renders a template to show the list.
.. code-block:: python
@app.route("/users/")
def user_list():
users = User.query.all()
return render_template("users.html", users=users)
This works for the user model, but let's say you also had more models
that needed list pages. You'd need to write another view function for
each model, even though the only thing that would change is the model
and template name.
Instead, you can write a :class:`View` subclass that will query a model
and render a template. As the first step, we'll convert the view to a
class without any customization.
.. code-block:: python
from flask.views import View
class UserList(View):
def dispatch_request(self):
users = User.query.all()
return render_template("users.html", objects=users)
app.add_url_rule("/users/", view_func=UserList.as_view("user_list"))
The :meth:`View.dispatch_request` method is the equivalent of the view
function. Calling :meth:`View.as_view` method will create a view
function that can be registered on the app with its
:meth:`~flask.Flask.add_url_rule` method. The first argument to
``as_view`` is the name to use to refer to the view with
:func:`~flask.url_for`.
.. note::
You can't decorate the class with ``@app.route()`` the way you'd
do with a basic view function.
Next, we need to be able to register the same view class for different
models and templates, to make it more useful than the original function.
The class will take two arguments, the model and template, and store
them on ``self``. Then ``dispatch_request`` can reference these instead
of hard-coded values.
.. code-block:: python
class ListView(View):
def __init__(self, model, template):
self.model = model
self.template = template
def dispatch_request(self):
items = self.model.query.all()
return render_template(self.template, items=items)
Remember, we create the view function with ``View.as_view()`` instead of
creating the class directly. Any extra arguments passed to ``as_view``
are then passed when creating the class. Now we can register the same
view to handle multiple models.
.. code-block:: python
app.add_url_rule(
"/users/",
view_func=ListView.as_view("user_list", User, "users.html"),
)
app.add_url_rule(
"/stories/",
view_func=ListView.as_view("story_list", Story, "stories.html"),
)
URL Variables
-------------
Any variables captured by the URL are passed as keyword arguments to the
``dispatch_request`` method, as they would be for a regular view
function.
.. code-block:: python
class DetailView(View):
def __init__(self, model):
self.model = model
self.template = f"{model.__name__.lower()}/detail.html"
def dispatch_request(self, id)
item = self.model.query.get_or_404(id)
return render_template(self.template, item=item)
app.add_url_rule(
"/users/<int:id>",
view_func=DetailView.as_view("user_detail", User)
)
View Lifetime and ``self``
--------------------------
By default, a new instance of the view class is created every time a
request is handled. This means that it is safe to write other data to
``self`` during the request, since the next request will not see it,
unlike other forms of global state.
However, if your view class needs to do a lot of complex initialization,
doing it for every request is unnecessary and can be inefficient. To
avoid this, set :attr:`View.init_every_request` to ``False``, which will
only create one instance of the class and use it for every request. In
this case, writing to ``self`` is not safe. If you need to store data
during the request, use :data:`~flask.g` instead.
In the ``ListView`` example, nothing writes to ``self`` during the
request, so it is more efficient to create a single instance.
.. code-block:: python
class ListView(View):
init_every_request = False
def __init__(self, model, template):
self.model = model
self.template = template
def dispatch_request(self):
items = self.model.query.all()
return render_template(self.template, items=items)
Different instances will still be created each for each ``as_view``
call, but not for each request to those views.
View Decorators
---------------
The view class itself is not the view function. View decorators need to
be applied to the view function returned by ``as_view``, not the class
itself. Set :attr:`View.decorators` to a list of decorators to apply.
.. code-block:: python
class UserList(View):
decorators = [cache(minutes=2), login_required]
app.add_url_rule('/users/', view_func=UserList.as_view())
If you didn't set ``decorators``, you could apply them manually instead.
This is equivalent to:
.. code-block:: python
view = UserList.as_view("users_list")
view = cache(minutes=2)(view)
view = login_required(view)
app.add_url_rule('/users/', view_func=view)
Keep in mind that order matters. If you're used to ``@decorator`` style,
this is equivalent to:
.. code-block:: python
@app.route("/users/")
@login_required
@cache(minutes=2)
def user_list():
...
Method Hints
------------
A common pattern is to register a view with ``methods=["GET", "POST"]``,
then check ``request.method == "POST"`` to decide what to do. Setting
:attr:`View.methods` is equivalent to passing the list of methods to
``add_url_rule`` or ``route``.
.. code-block:: python
class MyView(View):
methods = ["GET", "POST"]
def dispatch_request(self):
if request.method == "POST":
...
...
app.add_url_rule('/my-view', view_func=MyView.as_view('my-view'))
This is equivalent to the following, except further subclasses can
inherit or change the methods.
.. code-block:: python
app.add_url_rule(
"/my-view",
view_func=MyView.as_view("my-view"),
methods=["GET", "POST"],
)
Method Dispatching and APIs
---------------------------
For APIs it can be helpful to use a different function for each HTTP
method. :class:`MethodView` extends the basic :class:`View` to dispatch
to different methods of the class based on the request method. Each HTTP
method maps to a method of the class with the same (lowercase) name.
:class:`MethodView` automatically sets :attr:`View.methods` based on the
methods defined by the class. It even knows how to handle subclasses
that override or define other methods.
We can make a generic ``ItemAPI`` class that provides get (detail),
patch (edit), and delete methods for a given model. A ``GroupAPI`` can
provide get (list) and post (create) methods.
.. code-block:: python
from flask.views import MethodView
class ItemAPI(MethodView):
init_every_request = False
def __init__(self, model):
self.model = model
self.validator = generate_validator(model)
def _get_item(self, id):
return self.model.query.get_or_404(id)
def get(self, id):
item = self._get_item(id)
return jsonify(item.to_json())
def patch(self, id):
item = self._get_item(id)
errors = self.validator.validate(item, request.json)
if errors:
return jsonify(errors), 400
item.update_from_json(request.json)
db.session.commit()
return jsonify(item.to_json())
def delete(self, id):
item = self._get_item(id)
db.session.delete(item)
db.session.commit()
return "", 204
class GroupAPI(MethodView):
init_every_request = False
def __init__(self, model):
self.model = model
self.validator = generate_validator(model, create=True)
def get(self):
items = self.model.query.all()
return jsonify([item.to_json() for item in items])
def post(self):
errors = self.validator.validate(request.json)
if errors:
return jsonify(errors), 400
db.session.add(self.model.from_json(request.json))
db.session.commit()
return jsonify(item.to_json())
def register_api(app, model, name):
item = ItemAPI.as_view(f"{name}-item", model)
group = GroupAPI.as_view(f"{name}-group", model)
app.add_url_rule(f"/{name}/<int:id>", view_func=item)
app.add_url_rule(f"/{name}/", view_func=group)
register_api(app, User, "users")
register_api(app, Story, "stories")
This produces the following views, a standard REST API!
================= ========== ===================
URL Method Description
----------------- ---------- -------------------
``/users/`` ``GET`` List all users
``/users/`` ``POST`` Create a new user
``/users/<id>`` ``GET`` Show a single user
``/users/<id>`` ``PATCH`` Update a user
``/users/<id>`` ``DELETE`` Delete a user
``/stories/`` ``GET`` List all stories
``/stories/`` ``POST`` Create a new story
``/stories/<id>`` ``GET`` Show a single story
``/stories/<id>`` ``PATCH`` Update a story
``/stories/<id>`` ``DELETE`` Delete a story
================= ========== ===================

@ -0,0 +1,316 @@
Security Considerations
=======================
Web applications face many types of potential security problems, and it can be
hard to get everything right, or even to know what "right" is in general. Flask
tries to solve a few of these things by default, but there are other parts you
may have to take care of yourself. Many of these solutions are tradeoffs, and
will depend on each application's specific needs and threat model. Many hosting
platforms may take care of certain types of problems without the need for the
Flask application to handle them.
Resource Use
------------
A common category of attacks is "Denial of Service" (DoS or DDoS). This is a
very broad category, and different variants target different layers in a
deployed application. In general, something is done to increase how much
processing time or memory is used to handle each request, to the point where
there are not enough resources to handle legitimate requests.
Flask provides a few configuration options to handle resource use. They can
also be set on individual requests to customize only that request. The
documentation for each goes into more detail.
- :data:`MAX_CONTENT_LENGTH` or :attr:`.Request.max_content_length` controls
how much data will be read from a request. It is not set by default,
although it will still block truly unlimited streams unless the WSGI server
indicates support.
- :data:`MAX_FORM_MEMORY_SIZE` or :attr:`.Request.max_form_memory_size`
controls how large any non-file ``multipart/form-data`` field can be. It is
set to 500kB by default.
- :data:`MAX_FORM_PARTS` or :attr:`.Request.max_form_parts` controls how many
``multipart/form-data`` fields can be parsed. It is set to 1000 by default.
Combined with the default `max_form_memory_size`, this means that a form
will occupy at most 500MB of memory.
Regardless of these settings, you should also review what settings are available
from your operating system, container deployment (Docker etc), WSGI server, HTTP
server, and hosting platform. They typically have ways to set process resource
limits, timeouts, and other checks regardless of how Flask is configured.
.. _security-xss:
Cross-Site Scripting (XSS)
--------------------------
Cross site scripting is the concept of injecting arbitrary HTML (and with
it JavaScript) into the context of a website. To remedy this, developers
have to properly escape text so that it cannot include arbitrary HTML
tags. For more information on that have a look at the Wikipedia article
on `Cross-Site Scripting
<https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
Flask configures Jinja to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused
in templates, but there are still other places where you have to be
careful:
- generating HTML without the help of Jinja
- calling :class:`~markupsafe.Markup` on data submitted by users
- sending out HTML from uploaded files, never do that, use the
``Content-Disposition: attachment`` header to prevent that problem.
- sending out textfiles from uploaded files. Some browsers are using
content-type guessing based on the first few bytes so users could
trick a browser to execute HTML.
Another thing that is very important are unquoted attributes. While
Jinja can protect you from XSS issues by escaping HTML, there is one
thing it cannot protect you from: XSS by attribute injection. To counter
this possible attack vector, be sure to always quote your attributes with
either double or single quotes when using Jinja expressions in them:
.. sourcecode:: html+jinja
<input value="{{ value }}">
Why is this necessary? Because if you would not be doing that, an
attacker could easily inject custom JavaScript handlers. For example an
attacker could inject this piece of HTML+JavaScript:
.. sourcecode:: html
onmouseover=alert(document.cookie)
When the user would then move with the mouse over the input, the cookie
would be presented to the user in an alert window. But instead of showing
the cookie to the user, a good attacker might also execute any other
JavaScript code. In combination with CSS injections the attacker might
even make the element fill out the entire page so that the user would
just have to have the mouse anywhere on the page to trigger the attack.
There is one class of XSS issues that Jinja's escaping does not protect
against. The ``a`` tag's ``href`` attribute can contain a `javascript:` URI,
which the browser will execute when clicked if not secured properly.
.. sourcecode:: html
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
To prevent this, you'll need to set the :ref:`security-csp` response header.
Cross-Site Request Forgery (CSRF)
---------------------------------
Another big problem is CSRF. This is a very complex topic and I won't
outline it here in detail just mention what it is and how to theoretically
prevent it.
If your authentication information is stored in cookies, you have implicit
state management. The state of "being logged in" is controlled by a
cookie, and that cookie is sent with each request to a page.
Unfortunately that includes requests triggered by 3rd party sites. If you
don't keep that in mind, some people might be able to trick your
application's users with social engineering to do stupid things without
them knowing.
Say you have a specific URL that, when you sent ``POST`` requests to will
delete a user's profile (say ``http://example.com/user/delete``). If an
attacker now creates a page that sends a post request to that page with
some JavaScript they just have to trick some users to load that page and
their profiles will end up being deleted.
Imagine you were to run Facebook with millions of concurrent users and
someone would send out links to images of little kittens. When users
would go to that page, their profiles would get deleted while they are
looking at images of fluffy cats.
How can you prevent that? Basically for each request that modifies
content on the server you would have to either use a one-time token and
store that in the cookie **and** also transmit it with the form data.
After receiving the data on the server again, you would then have to
compare the two tokens and ensure they are equal.
Why does Flask not do that for you? The ideal place for this to happen is
the form validation framework, which does not exist in Flask.
.. _security-json:
JSON Security
-------------
In Flask 0.10 and lower, :func:`~flask.jsonify` did not serialize top-level
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.
ECMAScript 5 closed this vulnerability, so only extremely old browsers are
still vulnerable. All of these browsers have `other more serious
vulnerabilities
<https://github.com/pallets/flask/issues/248#issuecomment-59934857>`_, so
this behavior was changed and :func:`~flask.jsonify` now supports serializing
arrays.
Security Headers
----------------
Browsers recognize various response headers in order to control security. We
recommend reviewing each of the headers below for use in your application.
The `Flask-Talisman`_ extension can be used to manage HTTPS and the security
headers for you.
.. _Flask-Talisman: https://github.com/wntrblm/flask-talisman
HTTP Strict Transport Security (HSTS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the browser to convert all HTTP requests to HTTPS, preventing
man-in-the-middle (MITM) attacks. ::
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
.. _security-csp:
Content Security Policy (CSP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tell the browser where it can load various types of resource from. This header
should be used whenever possible, but requires some work to define the correct
policy for your site. A very strict policy would be::
response.headers['Content-Security-Policy'] = "default-src 'self'"
- https://csp.withgoogle.com/docs/index.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
X-Content-Type-Options
~~~~~~~~~~~~~~~~~~~~~~
Forces the browser to honor the response content type instead of trying to
detect it, which can be abused to generate a cross-site scripting (XSS)
attack. ::
response.headers['X-Content-Type-Options'] = 'nosniff'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
X-Frame-Options
~~~~~~~~~~~~~~~
Prevents external sites from embedding your site in an ``iframe``. This
prevents a class of attacks where clicks in the outer frame can be translated
invisibly to clicks on your page's elements. This is also known as
"clickjacking". ::
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
.. _security-cookie:
Set-Cookie options
~~~~~~~~~~~~~~~~~~
These options can be added to a ``Set-Cookie`` header to improve their
security. Flask has configuration options to set these on the session cookie.
They can be set on other cookies too.
- ``Secure`` limits cookies to HTTPS traffic only.
- ``HttpOnly`` protects the contents of cookies from being read with
JavaScript.
- ``SameSite`` restricts how cookies are sent with requests from
external sites. Can be set to ``'Lax'`` (recommended) or ``'Strict'``.
``Lax`` prevents sending cookies with CSRF-prone requests from
external sites, such as submitting a form. ``Strict`` prevents sending
cookies with all external requests, including following regular links.
::
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
response.set_cookie('username', 'flask', secure=True, httponly=True, samesite='Lax')
Specifying ``Expires`` or ``Max-Age`` options, will remove the cookie after
the given time, or the current time plus the age, respectively. If neither
option is set, the cookie will be removed when the browser is closed. ::
# cookie expires after 10 minutes
response.set_cookie('snakes', '3', max_age=600)
For the session cookie, if :attr:`session.permanent <flask.session.permanent>`
is set, then :data:`PERMANENT_SESSION_LIFETIME` is used to set the expiration.
Flask's default cookie implementation validates that the cryptographic
signature is not older than this value. Lowering this value may help mitigate
replay attacks, where intercepted cookies can be sent at a later time. ::
app.config.update(
PERMANENT_SESSION_LIFETIME=600
)
@app.route('/login', methods=['POST'])
def login():
...
session.clear()
session['user_id'] = user.id
session.permanent = True
...
Use :class:`itsdangerous.TimedSerializer` to sign and validate other cookie
values (or any values that need secure signatures).
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
Host Header Validation
----------------------
The ``Host`` header is used by the client to indicate what host name the request
was made to. This is used, for example, by ``url_for(..., _external=True)`` to
generate full URLs, for use in email or other messages outside the browser
window.
By default the app doesn't know what host(s) it is allowed to be accessed
through, and assumes any host is valid. Although browsers do not allow setting
the ``Host`` header, requests made by attackers in other scenarios could set
the ``Host`` header to a value they want.
When deploying your application, set :data:`TRUSTED_HOSTS` to restrict what
values the ``Host`` header may be.
The ``Host`` header may be modified by proxies in between the client and your
application. See :doc:`deploying/proxy_fix` to tell your app which proxy values
to trust.
Copy/Paste to Terminal
----------------------
Hidden characters such as the backspace character (``\b``, ``^H``) can
cause text to render differently in HTML than how it is interpreted if
`pasted into a terminal <https://security.stackexchange.com/q/39118>`__.
For example, ``import y\bose\bm\bi\bt\be\b`` renders as
``import yosemite`` in HTML, but the backspaces are applied when pasted
into a terminal, and it becomes ``import os``.
If you expect users to copy and paste untrusted code from your site,
such as from comments posted by users on a technical blog, consider
applying extra filtering, such as replacing all ``\b`` characters.
.. code-block:: python
body = body.replace("\b", "")
Most modern terminals will warn about and remove hidden characters when
pasting, so this isn't strictly necessary. It's also possible to craft
dangerous commands in other ways that aren't possible to filter.
Depending on your site's use case, it may be good to show a warning
about copying code in general.

@ -0,0 +1,27 @@
Background Tasks with Celery
============================
This example shows how to configure Celery with Flask, how to set up an API for
submitting tasks and polling results, and how to use that API with JavaScript. See
[Flask's documentation about Celery](https://flask.palletsprojects.com/patterns/celery/).
From this directory, create a virtualenv and install the application into it. Then run a
Celery worker.
```shell
$ python3 -m venv .venv
$ . ./.venv/bin/activate
$ pip install -r requirements.txt && pip install -e .
$ celery -A make_celery worker --loglevel INFO
```
In a separate terminal, activate the virtualenv and run the Flask development server.
```shell
$ . ./.venv/bin/activate
$ flask -A task_app run --debug
```
Go to http://localhost:5000/ and use the forms to submit tasks. You can see the polling
requests in the browser dev tools and the Flask logs. You can see the tasks submitting
and completing in the Celery logs.

@ -0,0 +1,4 @@
from task_app import create_app
flask_app = create_app()
celery_app = flask_app.extensions["celery"]

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save