├── .devcontainer
├── devcontainer.json
└── on-create-command.sh
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ ├── config.yml
│ └── feature-request.md
├── pull_request_template.md
└── workflows
│ ├── lock.yaml
│ ├── pre-commit.yaml
│ ├── publish.yaml
│ └── tests.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGES.rst
├── LICENSE.txt
├── README.md
├── docs
├── Makefile
├── _static
│ ├── debugger.png
│ ├── flask-horizontal.png
│ ├── flask-vertical.png
│ ├── pycharm-run-config.png
│ └── shortcut-icon.png
├── api.rst
├── appcontext.rst
├── async-await.rst
├── blueprints.rst
├── changes.rst
├── cli.rst
├── conf.py
├── config.rst
├── contributing.rst
├── debugging.rst
├── deploying
│ ├── apache-httpd.rst
│ ├── asgi.rst
│ ├── eventlet.rst
│ ├── gevent.rst
│ ├── gunicorn.rst
│ ├── index.rst
│ ├── mod_wsgi.rst
│ ├── nginx.rst
│ ├── proxy_fix.rst
│ ├── uwsgi.rst
│ └── waitress.rst
├── design.rst
├── errorhandling.rst
├── extensiondev.rst
├── extensions.rst
├── index.rst
├── installation.rst
├── license.rst
├── lifecycle.rst
├── logging.rst
├── make.bat
├── patterns
│ ├── appdispatch.rst
│ ├── appfactories.rst
│ ├── caching.rst
│ ├── celery.rst
│ ├── deferredcallbacks.rst
│ ├── favicon.rst
│ ├── fileuploads.rst
│ ├── flashing.rst
│ ├── index.rst
│ ├── javascript.rst
│ ├── jquery.rst
│ ├── lazyloading.rst
│ ├── methodoverrides.rst
│ ├── mongoengine.rst
│ ├── packages.rst
│ ├── requestchecksum.rst
│ ├── singlepageapplications.rst
│ ├── sqlalchemy.rst
│ ├── sqlite3.rst
│ ├── streaming.rst
│ ├── subclassing.rst
│ ├── templateinheritance.rst
│ ├── urlprocessors.rst
│ ├── viewdecorators.rst
│ └── wtforms.rst
├── quickstart.rst
├── reqcontext.rst
├── server.rst
├── shell.rst
├── signals.rst
├── templating.rst
├── testing.rst
├── tutorial
│ ├── blog.rst
│ ├── database.rst
│ ├── deploy.rst
│ ├── factory.rst
│ ├── flaskr_edit.png
│ ├── flaskr_index.png
│ ├── flaskr_login.png
│ ├── index.rst
│ ├── install.rst
│ ├── layout.rst
│ ├── next.rst
│ ├── static.rst
│ ├── templates.rst
│ ├── tests.rst
│ └── views.rst
├── views.rst
└── web-security.rst
├── examples
├── celery
│ ├── README.md
│ ├── make_celery.py
│ ├── pyproject.toml
│ ├── requirements.txt
│ └── src
│ │ └── task_app
│ │ ├── __init__.py
│ │ ├── tasks.py
│ │ ├── templates
│ │ └── index.html
│ │ └── views.py
├── javascript
│ ├── .gitignore
│ ├── LICENSE.txt
│ ├── README.rst
│ ├── js_example
│ │ ├── __init__.py
│ │ ├── templates
│ │ │ ├── base.html
│ │ │ ├── fetch.html
│ │ │ ├── jquery.html
│ │ │ └── xhr.html
│ │ └── views.py
│ ├── pyproject.toml
│ └── tests
│ │ ├── conftest.py
│ │ └── test_js_example.py
└── tutorial
│ ├── .gitignore
│ ├── LICENSE.txt
│ ├── README.rst
│ ├── flaskr
│ ├── __init__.py
│ ├── auth.py
│ ├── blog.py
│ ├── db.py
│ ├── schema.sql
│ ├── static
│ │ └── style.css
│ └── templates
│ │ ├── auth
│ │ ├── login.html
│ │ └── register.html
│ │ ├── base.html
│ │ └── blog
│ │ ├── create.html
│ │ ├── index.html
│ │ └── update.html
│ ├── pyproject.toml
│ └── tests
│ ├── conftest.py
│ ├── data.sql
│ ├── test_auth.py
│ ├── test_blog.py
│ ├── test_db.py
│ └── test_factory.py
├── pyproject.toml
├── src
└── flask
│ ├── __init__.py
│ ├── __main__.py
│ ├── app.py
│ ├── blueprints.py
│ ├── cli.py
│ ├── config.py
│ ├── ctx.py
│ ├── debughelpers.py
│ ├── globals.py
│ ├── helpers.py
│ ├── json
│ ├── __init__.py
│ ├── provider.py
│ └── tag.py
│ ├── logging.py
│ ├── py.typed
│ ├── sansio
│ ├── README.md
│ ├── app.py
│ ├── blueprints.py
│ └── scaffold.py
│ ├── sessions.py
│ ├── signals.py
│ ├── templating.py
│ ├── testing.py
│ ├── typing.py
│ ├── views.py
│ └── wrappers.py
├── tests
├── conftest.py
├── static
│ ├── config.json
│ ├── config.toml
│ └── index.html
├── templates
│ ├── _macro.html
│ ├── context_template.html
│ ├── escaping_template.html
│ ├── mail.txt
│ ├── nested
│ │ └── nested.txt
│ ├── non_escaping_template.txt
│ ├── simple_template.html
│ ├── template_filter.html
│ └── template_test.html
├── test_appctx.py
├── test_apps
│ ├── .env
│ ├── .flaskenv
│ ├── blueprintapp
│ │ ├── __init__.py
│ │ └── apps
│ │ │ ├── __init__.py
│ │ │ ├── admin
│ │ │ ├── __init__.py
│ │ │ ├── static
│ │ │ │ ├── css
│ │ │ │ │ └── test.css
│ │ │ │ └── test.txt
│ │ │ └── templates
│ │ │ │ └── admin
│ │ │ │ └── index.html
│ │ │ └── frontend
│ │ │ ├── __init__.py
│ │ │ └── templates
│ │ │ └── frontend
│ │ │ └── index.html
│ ├── cliapp
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── factory.py
│ │ ├── importerrorapp.py
│ │ ├── inner1
│ │ │ ├── __init__.py
│ │ │ └── inner2
│ │ │ │ ├── __init__.py
│ │ │ │ └── flask.py
│ │ ├── message.txt
│ │ └── multiapp.py
│ ├── helloworld
│ │ ├── hello.py
│ │ └── wsgi.py
│ └── subdomaintestmodule
│ │ ├── __init__.py
│ │ └── static
│ │ └── hello.txt
├── test_async.py
├── test_basic.py
├── test_blueprints.py
├── test_cli.py
├── test_config.py
├── test_converters.py
├── test_helpers.py
├── test_instance_config.py
├── test_json.py
├── test_json_tag.py
├── test_logging.py
├── test_regression.py
├── test_reqctx.py
├── test_request.py
├── test_session_interface.py
├── test_signals.py
├── test_subclassing.py
├── test_templating.py
├── test_testing.py
├── test_user_error_handler.py
├── test_views.py
└── type_check
│ ├── typing_app_decorators.py
│ ├── typing_error_handler.py
│ └── typing_route.py
└── uv.lock
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pallets/flask",
3 | "image": "mcr.microsoft.com/devcontainers/python:3",
4 | "customizations": {
5 | "vscode": {
6 | "settings": {
7 | "python.defaultInterpreterPath": "${workspaceFolder}/.venv",
8 | "python.terminal.activateEnvInCurrentTerminal": true,
9 | "python.terminal.launchArgs": [
10 | "-X",
11 | "dev"
12 | ]
13 | }
14 | }
15 | },
16 | "onCreateCommand": ".devcontainer/on-create-command.sh"
17 | }
18 |
--------------------------------------------------------------------------------
/.devcontainer/on-create-command.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | python3 -m venv --upgrade-deps .venv
4 | . .venv/bin/activate
5 | pip install -r requirements/dev.txt
6 | pip install -e .
7 | pre-commit install --install-hooks
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | end_of_line = lf
9 | charset = utf-8
10 | max_line_length = 88
11 |
12 | [*.{css,html,js,json,jsx,scss,ts,tsx,yaml,yml}]
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report a bug in Flask (not other projects which depend on Flask)
4 | ---
5 |
6 |
12 |
13 |
19 |
20 |
23 |
24 | Environment:
25 |
26 | - Python version:
27 | - Flask version:
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Security issue
4 | url: https://github.com/pallets/flask/security/advisories/new
5 | about: Do not report security issues publicly. Create a private advisory.
6 | - name: Questions on GitHub Discussions
7 | url: https://github.com/pallets/flask/discussions/
8 | about: Ask questions about your own code on the Discussions tab.
9 | - name: Questions on Discord
10 | url: https://discord.gg/pallets
11 | about: Ask questions about your own code on our Discord chat.
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest a new feature for Flask
4 | ---
5 |
6 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
9 |
10 |
16 |
17 |
26 |
--------------------------------------------------------------------------------
/.github/workflows/lock.yaml:
--------------------------------------------------------------------------------
1 | name: Lock inactive closed issues
2 | # Lock closed issues that have not received any further activity for two weeks.
3 | # This does not close open issues, only humans may do that. It is easier to
4 | # respond to new issues with fresh examples rather than continuing discussions
5 | # on old issues.
6 |
7 | on:
8 | schedule:
9 | - cron: '0 0 * * *'
10 | permissions:
11 | issues: write
12 | pull-requests: write
13 | discussions: write
14 | concurrency:
15 | group: lock
16 | jobs:
17 | lock:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
21 | with:
22 | issue-inactive-days: 14
23 | pr-inactive-days: 14
24 | discussion-inactive-days: 14
25 |
--------------------------------------------------------------------------------
/.github/workflows/pre-commit.yaml:
--------------------------------------------------------------------------------
1 | name: pre-commit
2 | on:
3 | pull_request:
4 | push:
5 | branches: [main, stable]
6 | jobs:
7 | main:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
11 | - uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
12 | with:
13 | enable-cache: true
14 | prune-cache: false
15 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
16 | id: setup-python
17 | with:
18 | python-version-file: pyproject.toml
19 | - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
20 | with:
21 | path: ~/.cache/pre-commit
22 | key: pre-commit|${{ hashFiles('pyproject.toml', '.pre-commit-config.yaml') }}
23 | - run: uv run --locked --group pre-commit pre-commit run --show-diff-on-failure --color=always --all-files
24 | - uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
25 | if: ${{ !cancelled() }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yaml:
--------------------------------------------------------------------------------
1 | name: Publish
2 | on:
3 | push:
4 | tags: ['*']
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | outputs:
9 | hash: ${{ steps.hash.outputs.hash }}
10 | steps:
11 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
12 | - uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
13 | with:
14 | enable-cache: true
15 | prune-cache: false
16 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
17 | with:
18 | python-version-file: pyproject.toml
19 | - run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
20 | - run: uv build
21 | - name: generate hash
22 | id: hash
23 | run: cd dist && echo "hash=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT
24 | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
25 | with:
26 | path: ./dist
27 | provenance:
28 | needs: [build]
29 | permissions:
30 | actions: read
31 | id-token: write
32 | contents: write
33 | # Can't pin with hash due to how this workflow works.
34 | uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
35 | with:
36 | base64-subjects: ${{ needs.build.outputs.hash }}
37 | create-release:
38 | needs: [provenance]
39 | runs-on: ubuntu-latest
40 | permissions:
41 | contents: write
42 | steps:
43 | - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
44 | - name: create release
45 | run: >
46 | gh release create --draft --repo ${{ github.repository }}
47 | ${{ github.ref_name }}
48 | *.intoto.jsonl/* artifact/*
49 | env:
50 | GH_TOKEN: ${{ github.token }}
51 | publish-pypi:
52 | needs: [provenance]
53 | environment:
54 | name: publish
55 | url: https://pypi.org/project/Flask/${{ github.ref_name }}
56 | runs-on: ubuntu-latest
57 | permissions:
58 | id-token: write
59 | steps:
60 | - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
61 | - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
62 | with:
63 | packages-dir: artifact/
64 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yaml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on:
3 | pull_request:
4 | paths-ignore: ['docs/**', 'README.md']
5 | push:
6 | branches: [main, stable]
7 | paths-ignore: ['docs/**', 'README.md']
8 | jobs:
9 | tests:
10 | name: ${{ matrix.name || matrix.python }}
11 | runs-on: ${{ matrix.os || 'ubuntu-latest' }}
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | include:
16 | - {python: '3.13'}
17 | - {name: Windows, python: '3.13', os: windows-latest}
18 | - {name: Mac, python: '3.13', os: macos-latest}
19 | - {python: '3.12'}
20 | - {python: '3.11'}
21 | - {python: '3.10'}
22 | - {name: PyPy, python: 'pypy-3.11', tox: pypy3.11}
23 | - {name: Minimum Versions, python: '3.13', tox: tests-min}
24 | - {name: Development Versions, python: '3.10', tox: tests-dev}
25 | steps:
26 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
27 | - uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
28 | with:
29 | enable-cache: true
30 | prune-cache: false
31 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
32 | with:
33 | python-version: ${{ matrix.python }}
34 | - run: uv run --locked tox run -e ${{ matrix.tox || format('py{0}', matrix.python) }}
35 | typing:
36 | runs-on: ubuntu-latest
37 | steps:
38 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
39 | - uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
40 | with:
41 | enable-cache: true
42 | prune-cache: false
43 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
44 | with:
45 | python-version-file: pyproject.toml
46 | - name: cache mypy
47 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
48 | with:
49 | path: ./.mypy_cache
50 | key: mypy|${{ hashFiles('pyproject.toml') }}
51 | - run: uv run --locked tox run -e typing
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | __pycache__/
4 | dist/
5 | .coverage*
6 | htmlcov/
7 | .tox/
8 | docs/_build/
9 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/astral-sh/ruff-pre-commit
3 | rev: 24e02b24b8ab2b7c76225602d13fa60e12d114e6 # frozen: v0.11.9
4 | hooks:
5 | - id: ruff
6 | - id: ruff-format
7 | - repo: https://github.com/astral-sh/uv-pre-commit
8 | rev: 14ac15b122e538e407d036ff45e3895b7cf4a2bf # frozen: 0.7.3
9 | hooks:
10 | - id: uv-lock
11 | - repo: https://github.com/pre-commit/pre-commit-hooks
12 | rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
13 | hooks:
14 | - id: check-merge-conflict
15 | - id: debug-statements
16 | - id: fix-byte-order-marker
17 | - id: trailing-whitespace
18 | - id: end-of-file-fixer
19 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | build:
3 | os: ubuntu-24.04
4 | tools:
5 | python: '3.13'
6 | commands:
7 | - asdf plugin add uv
8 | - asdf install uv latest
9 | - asdf global uv latest
10 | - uv run --group docs sphinx-build -W -b dirhtml docs $READTHEDOCS_OUTPUT/html
11 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2010 Pallets
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flask
2 |
3 | Flask is a lightweight [WSGI] web application framework. It is designed
4 | to make getting started quick and easy, with the ability to scale up to
5 | complex applications. It began as a simple wrapper around [Werkzeug]
6 | and [Jinja], and has become one of the most popular Python web
7 | application frameworks.
8 |
9 | Flask offers suggestions, but doesn't enforce any dependencies or
10 | project layout. It is up to the developer to choose the tools and
11 | libraries they want to use. There are many extensions provided by the
12 | community that make adding new functionality easy.
13 |
14 | [WSGI]: https://wsgi.readthedocs.io/
15 | [Werkzeug]: https://werkzeug.palletsprojects.com/
16 | [Jinja]: https://jinja.palletsprojects.com/
17 |
18 | ## A Simple Example
19 |
20 | ```python
21 | # save this as app.py
22 | from flask import Flask
23 |
24 | app = Flask(__name__)
25 |
26 | @app.route("/")
27 | def hello():
28 | return "Hello, World!"
29 | ```
30 |
31 | ```
32 | $ flask run
33 | * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
34 | ```
35 |
36 | ## Donate
37 |
38 | The Pallets organization develops and supports Flask and the libraries
39 | it uses. In order to grow the community of contributors and users, and
40 | allow the maintainers to devote more time to the projects, [please
41 | donate today].
42 |
43 | [please donate today]: https://palletsprojects.com/donate
44 |
45 | ## Contributing
46 |
47 | See our [detailed contributing documentation][contrib] for many ways to
48 | contribute, including reporting issues, requesting features, asking or answering
49 | questions, and making PRs.
50 |
51 | [contrib]: https://palletsprojects.com/contributing/
52 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/_static/debugger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/_static/debugger.png
--------------------------------------------------------------------------------
/docs/_static/flask-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/_static/flask-horizontal.png
--------------------------------------------------------------------------------
/docs/_static/flask-vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/_static/flask-vertical.png
--------------------------------------------------------------------------------
/docs/_static/pycharm-run-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/_static/pycharm-run-config.png
--------------------------------------------------------------------------------
/docs/_static/shortcut-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/_static/shortcut-icon.png
--------------------------------------------------------------------------------
/docs/changes.rst:
--------------------------------------------------------------------------------
1 | Changes
2 | =======
3 |
4 | .. include:: ../CHANGES.rst
5 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | import packaging.version
2 | from pallets_sphinx_themes import get_version
3 | from pallets_sphinx_themes import ProjectLink
4 |
5 | # Project --------------------------------------------------------------
6 |
7 | project = "Flask"
8 | copyright = "2010 Pallets"
9 | author = "Pallets"
10 | release, version = get_version("Flask")
11 |
12 | # General --------------------------------------------------------------
13 |
14 | default_role = "code"
15 | extensions = [
16 | "sphinx.ext.autodoc",
17 | "sphinx.ext.extlinks",
18 | "sphinx.ext.intersphinx",
19 | "sphinxcontrib.log_cabinet",
20 | "sphinx_tabs.tabs",
21 | "pallets_sphinx_themes",
22 | ]
23 | autodoc_member_order = "bysource"
24 | autodoc_typehints = "description"
25 | autodoc_preserve_defaults = True
26 | extlinks = {
27 | "issue": ("https://github.com/pallets/flask/issues/%s", "#%s"),
28 | "pr": ("https://github.com/pallets/flask/pull/%s", "#%s"),
29 | "ghsa": ("https://github.com/pallets/flask/security/advisories/GHSA-%s", "GHSA-%s"),
30 | }
31 | intersphinx_mapping = {
32 | "python": ("https://docs.python.org/3/", None),
33 | "werkzeug": ("https://werkzeug.palletsprojects.com/", None),
34 | "click": ("https://click.palletsprojects.com/", None),
35 | "jinja": ("https://jinja.palletsprojects.com/", None),
36 | "itsdangerous": ("https://itsdangerous.palletsprojects.com/", None),
37 | "sqlalchemy": ("https://docs.sqlalchemy.org/", None),
38 | "wtforms": ("https://wtforms.readthedocs.io/", None),
39 | "blinker": ("https://blinker.readthedocs.io/", None),
40 | }
41 |
42 | # HTML -----------------------------------------------------------------
43 |
44 | html_theme = "flask"
45 | html_theme_options = {"index_sidebar_logo": False}
46 | html_context = {
47 | "project_links": [
48 | ProjectLink("Donate", "https://palletsprojects.com/donate"),
49 | ProjectLink("PyPI Releases", "https://pypi.org/project/Flask/"),
50 | ProjectLink("Source Code", "https://github.com/pallets/flask/"),
51 | ProjectLink("Issue Tracker", "https://github.com/pallets/flask/issues/"),
52 | ProjectLink("Chat", "https://discord.gg/pallets"),
53 | ]
54 | }
55 | html_sidebars = {
56 | "index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"],
57 | "**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"],
58 | }
59 | singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
60 | html_static_path = ["_static"]
61 | html_favicon = "_static/shortcut-icon.png"
62 | html_logo = "_static/flask-vertical.png"
63 | html_title = f"Flask Documentation ({version})"
64 | html_show_sourcelink = False
65 |
66 | gettext_uuid = True
67 | gettext_compact = False
68 |
69 | # Local Extensions -----------------------------------------------------
70 |
71 |
72 | def github_link(name, rawtext, text, lineno, inliner, options=None, content=None):
73 | app = inliner.document.settings.env.app
74 | release = app.config.release
75 | base_url = "https://github.com/pallets/flask/tree/"
76 |
77 | if text.endswith(">"):
78 | words, text = text[:-1].rsplit("<", 1)
79 | words = words.strip()
80 | else:
81 | words = None
82 |
83 | if packaging.version.parse(release).is_devrelease:
84 | url = f"{base_url}main/{text}"
85 | else:
86 | url = f"{base_url}{release}/{text}"
87 |
88 | if words is None:
89 | words = url
90 |
91 | from docutils.nodes import reference
92 | from docutils.parsers.rst.roles import set_classes
93 |
94 | options = options or {}
95 | set_classes(options)
96 | node = reference(rawtext, words, refuri=url, **options)
97 | return [node], []
98 |
99 |
100 | def setup(app):
101 | app.add_role("gh", github_link)
102 |
--------------------------------------------------------------------------------
/docs/contributing.rst:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | See the Pallets `detailed contributing documentation <_contrib>`_ for many ways
5 | to contribute, including reporting issues, requesting features, asking or
6 | answering questions, and making PRs.
7 |
8 | .. _contrib: https://palletsprojects.com/contributing/
9 |
--------------------------------------------------------------------------------
/docs/debugging.rst:
--------------------------------------------------------------------------------
1 | Debugging Application Errors
2 | ============================
3 |
4 |
5 | In Production
6 | -------------
7 |
8 | **Do not run the development server, or enable the built-in debugger, in
9 | a production environment.** The debugger allows executing arbitrary
10 | Python code from the browser. It's protected by a pin, but that should
11 | not be relied on for security.
12 |
13 | Use an error logging tool, such as Sentry, as described in
14 | :ref:`error-logging-tools`, or enable logging and notifications as
15 | described in :doc:`/logging`.
16 |
17 | If you have access to the server, you could add some code to start an
18 | external debugger if ``request.remote_addr`` matches your IP. Some IDE
19 | debuggers also have a remote mode so breakpoints on the server can be
20 | interacted with locally. Only enable a debugger temporarily.
21 |
22 |
23 | The Built-In Debugger
24 | ---------------------
25 |
26 | The built-in Werkzeug development server provides a debugger which shows
27 | an interactive traceback in the browser when an unhandled error occurs
28 | during a request. This debugger should only be used during development.
29 |
30 | .. image:: _static/debugger.png
31 | :align: center
32 | :class: screenshot
33 | :alt: screenshot of debugger in action
34 |
35 | .. warning::
36 |
37 | The debugger allows executing arbitrary Python code from the
38 | browser. It is protected by a pin, but still represents a major
39 | security risk. Do not run the development server or debugger in a
40 | production environment.
41 |
42 | The debugger is enabled by default when the development server is run in debug mode.
43 |
44 | .. code-block:: text
45 |
46 | $ flask --app hello run --debug
47 |
48 | When running from Python code, passing ``debug=True`` enables debug mode, which is
49 | mostly equivalent.
50 |
51 | .. code-block:: python
52 |
53 | app.run(debug=True)
54 |
55 | :doc:`/server` and :doc:`/cli` have more information about running the debugger and
56 | debug mode. More information about the debugger can be found in the `Werkzeug
57 | documentation `__.
58 |
59 |
60 | External Debuggers
61 | ------------------
62 |
63 | External debuggers, such as those provided by IDEs, can offer a more
64 | powerful debugging experience than the built-in debugger. They can also
65 | be used to step through code during a request before an error is raised,
66 | or if no error is raised. Some even have a remote mode so you can debug
67 | code running on another machine.
68 |
69 | When using an external debugger, the app should still be in debug mode, otherwise Flask
70 | turns unhandled errors into generic 500 error pages. However, the built-in debugger and
71 | reloader should be disabled so they don't interfere with the external debugger.
72 |
73 | .. code-block:: text
74 |
75 | $ flask --app hello run --debug --no-debugger --no-reload
76 |
77 | When running from Python:
78 |
79 | .. code-block:: python
80 |
81 | app.run(debug=True, use_debugger=False, use_reloader=False)
82 |
83 | Disabling these isn't required, an external debugger will continue to work with the
84 | following caveats.
85 |
86 | - If the built-in debugger is not disabled, it will catch unhandled exceptions before
87 | the external debugger can.
88 | - If the reloader is not disabled, it could cause an unexpected reload if code changes
89 | during a breakpoint.
90 | - The development server will still catch unhandled exceptions if the built-in
91 | debugger is disabled, otherwise it would crash on any error. If you want that (and
92 | usually you don't) pass ``passthrough_errors=True`` to ``app.run``.
93 |
94 | .. code-block:: python
95 |
96 | app.run(
97 | debug=True, passthrough_errors=True,
98 | use_debugger=False, use_reloader=False
99 | )
100 |
--------------------------------------------------------------------------------
/docs/deploying/apache-httpd.rst:
--------------------------------------------------------------------------------
1 | Apache httpd
2 | ============
3 |
4 | `Apache httpd`_ is a fast, production level HTTP server. When serving
5 | your application with one of the WSGI servers listed in :doc:`index`, it
6 | is often good or necessary to put a dedicated HTTP server in front of
7 | it. This "reverse proxy" can handle incoming requests, TLS, and other
8 | security and performance concerns better than the WSGI server.
9 |
10 | httpd can be installed using your system package manager, or a pre-built
11 | executable for Windows. Installing and running httpd itself is outside
12 | the scope of this doc. This page outlines the basics of configuring
13 | httpd to proxy your application. Be sure to read its documentation to
14 | understand what features are available.
15 |
16 | .. _Apache httpd: https://httpd.apache.org/
17 |
18 |
19 | Domain Name
20 | -----------
21 |
22 | Acquiring and configuring a domain name is outside the scope of this
23 | doc. In general, you will buy a domain name from a registrar, pay for
24 | server space with a hosting provider, and then point your registrar
25 | at the hosting provider's name servers.
26 |
27 | To simulate this, you can also edit your ``hosts`` file, located at
28 | ``/etc/hosts`` on Linux. Add a line that associates a name with the
29 | local IP.
30 |
31 | Modern Linux systems may be configured to treat any domain name that
32 | ends with ``.localhost`` like this without adding it to the ``hosts``
33 | file.
34 |
35 | .. code-block:: python
36 | :caption: ``/etc/hosts``
37 |
38 | 127.0.0.1 hello.localhost
39 |
40 |
41 | Configuration
42 | -------------
43 |
44 | The httpd configuration is located at ``/etc/httpd/conf/httpd.conf`` on
45 | Linux. It may be different depending on your operating system. Check the
46 | docs and look for ``httpd.conf``.
47 |
48 | Remove or comment out any existing ``DocumentRoot`` directive. Add the
49 | config lines below. We'll assume the WSGI server is listening locally at
50 | ``http://127.0.0.1:8000``.
51 |
52 | .. code-block:: apache
53 | :caption: ``/etc/httpd/conf/httpd.conf``
54 |
55 | LoadModule proxy_module modules/mod_proxy.so
56 | LoadModule proxy_http_module modules/mod_proxy_http.so
57 | ProxyPass / http://127.0.0.1:8000/
58 | RequestHeader set X-Forwarded-Proto http
59 | RequestHeader set X-Forwarded-Prefix /
60 |
61 | The ``LoadModule`` lines might already exist. If so, make sure they are
62 | uncommented instead of adding them manually.
63 |
64 | Then :doc:`proxy_fix` so that your application uses the ``X-Forwarded``
65 | headers. ``X-Forwarded-For`` and ``X-Forwarded-Host`` are automatically
66 | set by ``ProxyPass``.
67 |
--------------------------------------------------------------------------------
/docs/deploying/asgi.rst:
--------------------------------------------------------------------------------
1 | ASGI
2 | ====
3 |
4 | If you'd like to use an ASGI server you will need to utilise WSGI to
5 | ASGI middleware. The asgiref
6 | `WsgiToAsgi `_
7 | adapter is recommended as it integrates with the event loop used for
8 | Flask's :ref:`async_await` support. You can use the adapter by
9 | wrapping the Flask app,
10 |
11 | .. code-block:: python
12 |
13 | from asgiref.wsgi import WsgiToAsgi
14 | from flask import Flask
15 |
16 | app = Flask(__name__)
17 |
18 | ...
19 |
20 | asgi_app = WsgiToAsgi(app)
21 |
22 | and then serving the ``asgi_app`` with the ASGI server, e.g. using
23 | `Hypercorn `_,
24 |
25 | .. sourcecode:: text
26 |
27 | $ hypercorn module:asgi_app
28 |
--------------------------------------------------------------------------------
/docs/deploying/eventlet.rst:
--------------------------------------------------------------------------------
1 | eventlet
2 | ========
3 |
4 | Prefer using :doc:`gunicorn` with eventlet workers rather than using
5 | `eventlet`_ directly. Gunicorn provides a much more configurable and
6 | production-tested server.
7 |
8 | `eventlet`_ allows writing asynchronous, coroutine-based code that looks
9 | like standard synchronous Python. It uses `greenlet`_ to enable task
10 | switching without writing ``async/await`` or using ``asyncio``.
11 |
12 | :doc:`gevent` is another library that does the same thing. Certain
13 | dependencies you have, or other considerations, may affect which of the
14 | two you choose to use.
15 |
16 | eventlet provides a WSGI server that can handle many connections at once
17 | instead of one per worker process. You must actually use eventlet in
18 | your own code to see any benefit to using the server.
19 |
20 | .. _eventlet: https://eventlet.net/
21 | .. _greenlet: https://greenlet.readthedocs.io/en/latest/
22 |
23 |
24 | Installing
25 | ----------
26 |
27 | When using eventlet, greenlet>=1.0 is required, otherwise context locals
28 | such as ``request`` will not work as expected. When using PyPy,
29 | PyPy>=7.3.7 is required.
30 |
31 | Create a virtualenv, install your application, then install
32 | ``eventlet``.
33 |
34 | .. code-block:: text
35 |
36 | $ cd hello-app
37 | $ python -m venv .venv
38 | $ . .venv/bin/activate
39 | $ pip install . # install your application
40 | $ pip install eventlet
41 |
42 |
43 | Running
44 | -------
45 |
46 | To use eventlet to serve your application, write a script that imports
47 | its ``wsgi.server``, as well as your app or app factory.
48 |
49 | .. code-block:: python
50 | :caption: ``wsgi.py``
51 |
52 | import eventlet
53 | from eventlet import wsgi
54 | from hello import create_app
55 |
56 | app = create_app()
57 | wsgi.server(eventlet.listen(("127.0.0.1", 8000)), app)
58 |
59 | .. code-block:: text
60 |
61 | $ python wsgi.py
62 | (x) wsgi starting up on http://127.0.0.1:8000
63 |
64 |
65 | Binding Externally
66 | ------------------
67 |
68 | eventlet should not be run as root because it would cause your
69 | application code to run as root, which is not secure. However, this
70 | means it will not be possible to bind to port 80 or 443. Instead, a
71 | reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
72 | in front of eventlet.
73 |
74 | You can bind to all external IPs on a non-privileged port by using
75 | ``0.0.0.0`` in the server arguments shown in the previous section.
76 | Don't do this when using a reverse proxy setup, otherwise it will be
77 | possible to bypass the proxy.
78 |
79 | ``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
80 | IP address in your browser.
81 |
--------------------------------------------------------------------------------
/docs/deploying/gevent.rst:
--------------------------------------------------------------------------------
1 | gevent
2 | ======
3 |
4 | Prefer using :doc:`gunicorn` or :doc:`uwsgi` with gevent workers rather
5 | than using `gevent`_ directly. Gunicorn and uWSGI provide much more
6 | configurable and production-tested servers.
7 |
8 | `gevent`_ allows writing asynchronous, coroutine-based code that looks
9 | like standard synchronous Python. It uses `greenlet`_ to enable task
10 | switching without writing ``async/await`` or using ``asyncio``.
11 |
12 | :doc:`eventlet` is another library that does the same thing. Certain
13 | dependencies you have, or other considerations, may affect which of the
14 | two you choose to use.
15 |
16 | gevent provides a WSGI server that can handle many connections at once
17 | instead of one per worker process. You must actually use gevent in your
18 | own code to see any benefit to using the server.
19 |
20 | .. _gevent: https://www.gevent.org/
21 | .. _greenlet: https://greenlet.readthedocs.io/en/latest/
22 |
23 |
24 | Installing
25 | ----------
26 |
27 | When using gevent, greenlet>=1.0 is required, otherwise context locals
28 | such as ``request`` will not work as expected. When using PyPy,
29 | PyPy>=7.3.7 is required.
30 |
31 | Create a virtualenv, install your application, then install ``gevent``.
32 |
33 | .. code-block:: text
34 |
35 | $ cd hello-app
36 | $ python -m venv .venv
37 | $ . .venv/bin/activate
38 | $ pip install . # install your application
39 | $ pip install gevent
40 |
41 |
42 | Running
43 | -------
44 |
45 | To use gevent to serve your application, write a script that imports its
46 | ``WSGIServer``, as well as your app or app factory.
47 |
48 | .. code-block:: python
49 | :caption: ``wsgi.py``
50 |
51 | from gevent.pywsgi import WSGIServer
52 | from hello import create_app
53 |
54 | app = create_app()
55 | http_server = WSGIServer(("127.0.0.1", 8000), app)
56 | http_server.serve_forever()
57 |
58 | .. code-block:: text
59 |
60 | $ python wsgi.py
61 |
62 | No output is shown when the server starts.
63 |
64 |
65 | Binding Externally
66 | ------------------
67 |
68 | gevent should not be run as root because it would cause your
69 | application code to run as root, which is not secure. However, this
70 | means it will not be possible to bind to port 80 or 443. Instead, a
71 | reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
72 | in front of gevent.
73 |
74 | You can bind to all external IPs on a non-privileged port by using
75 | ``0.0.0.0`` in the server arguments shown in the previous section. Don't
76 | do this when using a reverse proxy setup, otherwise it will be possible
77 | to bypass the proxy.
78 |
79 | ``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
80 | IP address in your browser.
81 |
--------------------------------------------------------------------------------
/docs/deploying/gunicorn.rst:
--------------------------------------------------------------------------------
1 | Gunicorn
2 | ========
3 |
4 | `Gunicorn`_ is a pure Python WSGI server with simple configuration and
5 | multiple worker implementations for performance tuning.
6 |
7 | * It tends to integrate easily with hosting platforms.
8 | * It does not support Windows (but does run on WSL).
9 | * It is easy to install as it does not require additional dependencies
10 | or compilation.
11 | * It has built-in async worker support using gevent or eventlet.
12 |
13 | This page outlines the basics of running Gunicorn. Be sure to read its
14 | `documentation`_ and use ``gunicorn --help`` to understand what features
15 | are available.
16 |
17 | .. _Gunicorn: https://gunicorn.org/
18 | .. _documentation: https://docs.gunicorn.org/
19 |
20 |
21 | Installing
22 | ----------
23 |
24 | Gunicorn is easy to install, as it does not require external
25 | dependencies or compilation. It runs on Windows only under WSL.
26 |
27 | Create a virtualenv, install your application, then install
28 | ``gunicorn``.
29 |
30 | .. code-block:: text
31 |
32 | $ cd hello-app
33 | $ python -m venv .venv
34 | $ . .venv/bin/activate
35 | $ pip install . # install your application
36 | $ pip install gunicorn
37 |
38 |
39 | Running
40 | -------
41 |
42 | The only required argument to Gunicorn tells it how to load your Flask
43 | application. The syntax is ``{module_import}:{app_variable}``.
44 | ``module_import`` is the dotted import name to the module with your
45 | application. ``app_variable`` is the variable with the application. It
46 | can also be a function call (with any arguments) if you're using the
47 | app factory pattern.
48 |
49 | .. code-block:: text
50 |
51 | # equivalent to 'from hello import app'
52 | $ gunicorn -w 4 'hello:app'
53 |
54 | # equivalent to 'from hello import create_app; create_app()'
55 | $ gunicorn -w 4 'hello:create_app()'
56 |
57 | Starting gunicorn 20.1.0
58 | Listening at: http://127.0.0.1:8000 (x)
59 | Using worker: sync
60 | Booting worker with pid: x
61 | Booting worker with pid: x
62 | Booting worker with pid: x
63 | Booting worker with pid: x
64 |
65 | The ``-w`` option specifies the number of processes to run; a starting
66 | value could be ``CPU * 2``. The default is only 1 worker, which is
67 | probably not what you want for the default worker type.
68 |
69 | Logs for each request aren't shown by default, only worker info and
70 | errors are shown. To show access logs on stdout, use the
71 | ``--access-logfile=-`` option.
72 |
73 |
74 | Binding Externally
75 | ------------------
76 |
77 | Gunicorn should not be run as root because it would cause your
78 | application code to run as root, which is not secure. However, this
79 | means it will not be possible to bind to port 80 or 443. Instead, a
80 | reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
81 | in front of Gunicorn.
82 |
83 | You can bind to all external IPs on a non-privileged port using the
84 | ``-b 0.0.0.0`` option. Don't do this when using a reverse proxy setup,
85 | otherwise it will be possible to bypass the proxy.
86 |
87 | .. code-block:: text
88 |
89 | $ gunicorn -w 4 -b 0.0.0.0 'hello:create_app()'
90 | Listening at: http://0.0.0.0:8000 (x)
91 |
92 | ``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
93 | IP address in your browser.
94 |
95 |
96 | Async with gevent or eventlet
97 | -----------------------------
98 |
99 | The default sync worker is appropriate for many use cases. If you need
100 | asynchronous support, Gunicorn provides workers using either `gevent`_
101 | or `eventlet`_. This is not the same as Python's ``async/await``, or the
102 | ASGI server spec. You must actually use gevent/eventlet in your own code
103 | to see any benefit to using the workers.
104 |
105 | When using either gevent or eventlet, greenlet>=1.0 is required,
106 | otherwise context locals such as ``request`` will not work as expected.
107 | When using PyPy, PyPy>=7.3.7 is required.
108 |
109 | To use gevent:
110 |
111 | .. code-block:: text
112 |
113 | $ gunicorn -k gevent 'hello:create_app()'
114 | Starting gunicorn 20.1.0
115 | Listening at: http://127.0.0.1:8000 (x)
116 | Using worker: gevent
117 | Booting worker with pid: x
118 |
119 | To use eventlet:
120 |
121 | .. code-block:: text
122 |
123 | $ gunicorn -k eventlet 'hello:create_app()'
124 | Starting gunicorn 20.1.0
125 | Listening at: http://127.0.0.1:8000 (x)
126 | Using worker: eventlet
127 | Booting worker with pid: x
128 |
129 | .. _gevent: https://www.gevent.org/
130 | .. _eventlet: https://eventlet.net/
131 |
--------------------------------------------------------------------------------
/docs/deploying/index.rst:
--------------------------------------------------------------------------------
1 | Deploying to Production
2 | =======================
3 |
4 | After developing your application, you'll want to make it available
5 | publicly to other users. When you're developing locally, you're probably
6 | using the built-in development server, debugger, and reloader. These
7 | should not be used in production. Instead, you should use a dedicated
8 | WSGI server or hosting platform, some of which will be described here.
9 |
10 | "Production" means "not development", which applies whether you're
11 | serving your application publicly to millions of users or privately /
12 | locally to a single user. **Do not use the development server when
13 | deploying to production. It is intended for use only during local
14 | development. It is not designed to be particularly secure, stable, or
15 | efficient.**
16 |
17 | Self-Hosted Options
18 | -------------------
19 |
20 | Flask is a WSGI *application*. A WSGI *server* is used to run the
21 | application, converting incoming HTTP requests to the standard WSGI
22 | environ, and converting outgoing WSGI responses to HTTP responses.
23 |
24 | The primary goal of these docs is to familiarize you with the concepts
25 | involved in running a WSGI application using a production WSGI server
26 | and HTTP server. There are many WSGI servers and HTTP servers, with many
27 | configuration possibilities. The pages below discuss the most common
28 | servers, and show the basics of running each one. The next section
29 | discusses platforms that can manage this for you.
30 |
31 | .. toctree::
32 | :maxdepth: 1
33 |
34 | gunicorn
35 | waitress
36 | mod_wsgi
37 | uwsgi
38 | gevent
39 | eventlet
40 | asgi
41 |
42 | WSGI servers have HTTP servers built-in. However, a dedicated HTTP
43 | server may be safer, more efficient, or more capable. Putting an HTTP
44 | server in front of the WSGI server is called a "reverse proxy."
45 |
46 | .. toctree::
47 | :maxdepth: 1
48 |
49 | proxy_fix
50 | nginx
51 | apache-httpd
52 |
53 | This list is not exhaustive, and you should evaluate these and other
54 | servers based on your application's needs. Different servers will have
55 | different capabilities, configuration, and support.
56 |
57 |
58 | Hosting Platforms
59 | -----------------
60 |
61 | There are many services available for hosting web applications without
62 | needing to maintain your own server, networking, domain, etc. Some
63 | services may have a free tier up to a certain time or bandwidth. Many of
64 | these services use one of the WSGI servers described above, or a similar
65 | interface. The links below are for some of the most common platforms,
66 | which have instructions for Flask, WSGI, or Python.
67 |
68 | - `PythonAnywhere `_
69 | - `Google App Engine `_
70 | - `Google Cloud Run `_
71 | - `AWS Elastic Beanstalk `_
72 | - `Microsoft Azure `_
73 |
74 | This list is not exhaustive, and you should evaluate these and other
75 | services based on your application's needs. Different services will have
76 | different capabilities, configuration, pricing, and support.
77 |
78 | You'll probably need to :doc:`proxy_fix` when using most hosting
79 | platforms.
80 |
--------------------------------------------------------------------------------
/docs/deploying/mod_wsgi.rst:
--------------------------------------------------------------------------------
1 | mod_wsgi
2 | ========
3 |
4 | `mod_wsgi`_ is a WSGI server integrated with the `Apache httpd`_ server.
5 | The modern `mod_wsgi-express`_ command makes it easy to configure and
6 | start the server without needing to write Apache httpd configuration.
7 |
8 | * Tightly integrated with Apache httpd.
9 | * Supports Windows directly.
10 | * Requires a compiler and the Apache development headers to install.
11 | * Does not require a reverse proxy setup.
12 |
13 | This page outlines the basics of running mod_wsgi-express, not the more
14 | complex installation and configuration with httpd. Be sure to read the
15 | `mod_wsgi-express`_, `mod_wsgi`_, and `Apache httpd`_ documentation to
16 | understand what features are available.
17 |
18 | .. _mod_wsgi-express: https://pypi.org/project/mod-wsgi/
19 | .. _mod_wsgi: https://modwsgi.readthedocs.io/
20 | .. _Apache httpd: https://httpd.apache.org/
21 |
22 |
23 | Installing
24 | ----------
25 |
26 | Installing mod_wsgi requires a compiler and the Apache server and
27 | development headers installed. You will get an error if they are not.
28 | How to install them depends on the OS and package manager that you use.
29 |
30 | Create a virtualenv, install your application, then install
31 | ``mod_wsgi``.
32 |
33 | .. code-block:: text
34 |
35 | $ cd hello-app
36 | $ python -m venv .venv
37 | $ . .venv/bin/activate
38 | $ pip install . # install your application
39 | $ pip install mod_wsgi
40 |
41 |
42 | Running
43 | -------
44 |
45 | The only argument to ``mod_wsgi-express`` specifies a script containing
46 | your Flask application, which must be called ``application``. You can
47 | write a small script to import your app with this name, or to create it
48 | if using the app factory pattern.
49 |
50 | .. code-block:: python
51 | :caption: ``wsgi.py``
52 |
53 | from hello import app
54 |
55 | application = app
56 |
57 | .. code-block:: python
58 | :caption: ``wsgi.py``
59 |
60 | from hello import create_app
61 |
62 | application = create_app()
63 |
64 | Now run the ``mod_wsgi-express start-server`` command.
65 |
66 | .. code-block:: text
67 |
68 | $ mod_wsgi-express start-server wsgi.py --processes 4
69 |
70 | The ``--processes`` option specifies the number of worker processes to
71 | run; a starting value could be ``CPU * 2``.
72 |
73 | Logs for each request aren't show in the terminal. If an error occurs,
74 | its information is written to the error log file shown when starting the
75 | server.
76 |
77 |
78 | Binding Externally
79 | ------------------
80 |
81 | Unlike the other WSGI servers in these docs, mod_wsgi can be run as
82 | root to bind to privileged ports like 80 and 443. However, it must be
83 | configured to drop permissions to a different user and group for the
84 | worker processes.
85 |
86 | For example, if you created a ``hello`` user and group, you should
87 | install your virtualenv and application as that user, then tell
88 | mod_wsgi to drop to that user after starting.
89 |
90 | .. code-block:: text
91 |
92 | $ sudo /home/hello/.venv/bin/mod_wsgi-express start-server \
93 | /home/hello/wsgi.py \
94 | --user hello --group hello --port 80 --processes 4
95 |
--------------------------------------------------------------------------------
/docs/deploying/nginx.rst:
--------------------------------------------------------------------------------
1 | nginx
2 | =====
3 |
4 | `nginx`_ is a fast, production level HTTP server. When serving your
5 | application with one of the WSGI servers listed in :doc:`index`, it is
6 | often good or necessary to put a dedicated HTTP server in front of it.
7 | This "reverse proxy" can handle incoming requests, TLS, and other
8 | security and performance concerns better than the WSGI server.
9 |
10 | Nginx can be installed using your system package manager, or a pre-built
11 | executable for Windows. Installing and running Nginx itself is outside
12 | the scope of this doc. This page outlines the basics of configuring
13 | Nginx to proxy your application. Be sure to read its documentation to
14 | understand what features are available.
15 |
16 | .. _nginx: https://nginx.org/
17 |
18 |
19 | Domain Name
20 | -----------
21 |
22 | Acquiring and configuring a domain name is outside the scope of this
23 | doc. In general, you will buy a domain name from a registrar, pay for
24 | server space with a hosting provider, and then point your registrar
25 | at the hosting provider's name servers.
26 |
27 | To simulate this, you can also edit your ``hosts`` file, located at
28 | ``/etc/hosts`` on Linux. Add a line that associates a name with the
29 | local IP.
30 |
31 | Modern Linux systems may be configured to treat any domain name that
32 | ends with ``.localhost`` like this without adding it to the ``hosts``
33 | file.
34 |
35 | .. code-block:: python
36 | :caption: ``/etc/hosts``
37 |
38 | 127.0.0.1 hello.localhost
39 |
40 |
41 | Configuration
42 | -------------
43 |
44 | The nginx configuration is located at ``/etc/nginx/nginx.conf`` on
45 | Linux. It may be different depending on your operating system. Check the
46 | docs and look for ``nginx.conf``.
47 |
48 | Remove or comment out any existing ``server`` section. Add a ``server``
49 | section and use the ``proxy_pass`` directive to point to the address the
50 | WSGI server is listening on. We'll assume the WSGI server is listening
51 | locally at ``http://127.0.0.1:8000``.
52 |
53 | .. code-block:: nginx
54 | :caption: ``/etc/nginx.conf``
55 |
56 | server {
57 | listen 80;
58 | server_name _;
59 |
60 | location / {
61 | proxy_pass http://127.0.0.1:8000/;
62 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63 | proxy_set_header X-Forwarded-Proto $scheme;
64 | proxy_set_header X-Forwarded-Host $host;
65 | proxy_set_header X-Forwarded-Prefix /;
66 | }
67 | }
68 |
69 | Then :doc:`proxy_fix` so that your application uses these headers.
70 |
--------------------------------------------------------------------------------
/docs/deploying/proxy_fix.rst:
--------------------------------------------------------------------------------
1 | Tell Flask it is Behind a Proxy
2 | ===============================
3 |
4 | When using a reverse proxy, or many Python hosting platforms, the proxy
5 | will intercept and forward all external requests to the local WSGI
6 | server.
7 |
8 | From the WSGI server and Flask application's perspectives, requests are
9 | now coming from the HTTP server to the local address, rather than from
10 | the remote address to the external server address.
11 |
12 | HTTP servers should set ``X-Forwarded-`` headers to pass on the real
13 | values to the application. The application can then be told to trust and
14 | use those values by wrapping it with the
15 | :doc:`werkzeug:middleware/proxy_fix` middleware provided by Werkzeug.
16 |
17 | This middleware should only be used if the application is actually
18 | behind a proxy, and should be configured with the number of proxies that
19 | are chained in front of it. Not all proxies set all the headers. Since
20 | incoming headers can be faked, you must set how many proxies are setting
21 | each header so the middleware knows what to trust.
22 |
23 | .. code-block:: python
24 |
25 | from werkzeug.middleware.proxy_fix import ProxyFix
26 |
27 | app.wsgi_app = ProxyFix(
28 | app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
29 | )
30 |
31 | Remember, only apply this middleware if you are behind a proxy, and set
32 | the correct number of proxies that set each header. It can be a security
33 | issue if you get this configuration wrong.
34 |
--------------------------------------------------------------------------------
/docs/deploying/waitress.rst:
--------------------------------------------------------------------------------
1 | Waitress
2 | ========
3 |
4 | `Waitress`_ is a pure Python WSGI server.
5 |
6 | * It is easy to configure.
7 | * It supports Windows directly.
8 | * It is easy to install as it does not require additional dependencies
9 | or compilation.
10 | * It does not support streaming requests, full request data is always
11 | buffered.
12 | * It uses a single process with multiple thread workers.
13 |
14 | This page outlines the basics of running Waitress. Be sure to read its
15 | documentation and ``waitress-serve --help`` to understand what features
16 | are available.
17 |
18 | .. _Waitress: https://docs.pylonsproject.org/projects/waitress/
19 |
20 |
21 | Installing
22 | ----------
23 |
24 | Create a virtualenv, install your application, then install
25 | ``waitress``.
26 |
27 | .. code-block:: text
28 |
29 | $ cd hello-app
30 | $ python -m venv .venv
31 | $ . .venv/bin/activate
32 | $ pip install . # install your application
33 | $ pip install waitress
34 |
35 |
36 | Running
37 | -------
38 |
39 | The only required argument to ``waitress-serve`` tells it how to load
40 | your Flask application. The syntax is ``{module}:{app}``. ``module`` is
41 | the dotted import name to the module with your application. ``app`` is
42 | the variable with the application. If you're using the app factory
43 | pattern, use ``--call {module}:{factory}`` instead.
44 |
45 | .. code-block:: text
46 |
47 | # equivalent to 'from hello import app'
48 | $ waitress-serve --host 127.0.0.1 hello:app
49 |
50 | # equivalent to 'from hello import create_app; create_app()'
51 | $ waitress-serve --host 127.0.0.1 --call hello:create_app
52 |
53 | Serving on http://127.0.0.1:8080
54 |
55 | The ``--host`` option binds the server to local ``127.0.0.1`` only.
56 |
57 | Logs for each request aren't shown, only errors are shown. Logging can
58 | be configured through the Python interface instead of the command line.
59 |
60 |
61 | Binding Externally
62 | ------------------
63 |
64 | Waitress should not be run as root because it would cause your
65 | application code to run as root, which is not secure. However, this
66 | means it will not be possible to bind to port 80 or 443. Instead, a
67 | reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
68 | in front of Waitress.
69 |
70 | You can bind to all external IPs on a non-privileged port by not
71 | specifying the ``--host`` option. Don't do this when using a reverse
72 | proxy setup, otherwise it will be possible to bypass the proxy.
73 |
74 | ``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
75 | IP address in your browser.
76 |
--------------------------------------------------------------------------------
/docs/extensions.rst:
--------------------------------------------------------------------------------
1 | Extensions
2 | ==========
3 |
4 | Extensions are extra packages that add functionality to a Flask
5 | application. For example, an extension might add support for sending
6 | email or connecting to a database. Some extensions add entire new
7 | frameworks to help build certain types of applications, like a REST API.
8 |
9 |
10 | Finding Extensions
11 | ------------------
12 |
13 | Flask extensions are usually named "Flask-Foo" or "Foo-Flask". You can
14 | search PyPI for packages tagged with `Framework :: Flask `_.
15 |
16 |
17 | Using Extensions
18 | ----------------
19 |
20 | Consult each extension's documentation for installation, configuration,
21 | and usage instructions. Generally, extensions pull their own
22 | configuration from :attr:`app.config ` and are
23 | passed an application instance during initialization. For example,
24 | an extension called "Flask-Foo" might be used like this::
25 |
26 | from flask_foo import Foo
27 |
28 | foo = Foo()
29 |
30 | app = Flask(__name__)
31 | app.config.update(
32 | FOO_BAR='baz',
33 | FOO_SPAM='eggs',
34 | )
35 |
36 | foo.init_app(app)
37 |
38 |
39 | Building Extensions
40 | -------------------
41 |
42 | While `PyPI `_ contains many Flask extensions, you may not find
43 | an extension that fits your need. If this is the case, you can create
44 | your own, and publish it for others to use as well. Read
45 | :doc:`extensiondev` to develop your own Flask extension.
46 |
47 |
48 | .. _pypi: https://pypi.org/search/?c=Framework+%3A%3A+Flask
49 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. rst-class:: hide-header
2 |
3 | Welcome to Flask
4 | ================
5 |
6 | .. image:: _static/flask-horizontal.png
7 | :align: center
8 |
9 | Welcome to Flask's documentation. Flask is a lightweight WSGI web application framework.
10 | It is designed to make getting started quick and easy, with the ability to scale up to
11 | complex applications.
12 |
13 | Get started with :doc:`installation`
14 | and then get an overview with the :doc:`quickstart`. There is also a
15 | more detailed :doc:`tutorial/index` that shows how to create a small but
16 | complete application with Flask. Common patterns are described in the
17 | :doc:`patterns/index` section. The rest of the docs describe each
18 | component of Flask in detail, with a full reference in the :doc:`api`
19 | section.
20 |
21 | Flask depends on the `Werkzeug`_ WSGI toolkit, the `Jinja`_ template engine, and the
22 | `Click`_ CLI toolkit. Be sure to check their documentation as well as Flask's when
23 | looking for information.
24 |
25 | .. _Werkzeug: https://werkzeug.palletsprojects.com
26 | .. _Jinja: https://jinja.palletsprojects.com
27 | .. _Click: https://click.palletsprojects.com
28 |
29 |
30 | User's Guide
31 | ------------
32 |
33 | Flask provides configuration and conventions, with sensible defaults, to get started.
34 | This section of the documentation explains the different parts of the Flask framework
35 | and how they can be used, customized, and extended. Beyond Flask itself, look for
36 | community-maintained extensions to add even more functionality.
37 |
38 | .. toctree::
39 | :maxdepth: 2
40 |
41 | installation
42 | quickstart
43 | tutorial/index
44 | templating
45 | testing
46 | errorhandling
47 | debugging
48 | logging
49 | config
50 | signals
51 | views
52 | lifecycle
53 | appcontext
54 | reqcontext
55 | blueprints
56 | extensions
57 | cli
58 | server
59 | shell
60 | patterns/index
61 | web-security
62 | deploying/index
63 | async-await
64 |
65 |
66 | API Reference
67 | -------------
68 |
69 | If you are looking for information on a specific function, class or
70 | method, this part of the documentation is for you.
71 |
72 | .. toctree::
73 | :maxdepth: 2
74 |
75 | api
76 |
77 |
78 | Additional Notes
79 | ----------------
80 |
81 | .. toctree::
82 | :maxdepth: 2
83 |
84 | design
85 | extensiondev
86 | contributing
87 | license
88 | changes
89 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 |
5 | Python Version
6 | --------------
7 |
8 | We recommend using the latest version of Python. Flask supports Python 3.10 and newer.
9 |
10 |
11 | Dependencies
12 | ------------
13 |
14 | These distributions will be installed automatically when installing Flask.
15 |
16 | * `Werkzeug`_ implements WSGI, the standard Python interface between
17 | applications and servers.
18 | * `Jinja`_ is a template language that renders the pages your application
19 | serves.
20 | * `MarkupSafe`_ comes with Jinja. It escapes untrusted input when rendering
21 | templates to avoid injection attacks.
22 | * `ItsDangerous`_ securely signs data to ensure its integrity. This is used
23 | to protect Flask's session cookie.
24 | * `Click`_ is a framework for writing command line applications. It provides
25 | the ``flask`` command and allows adding custom management commands.
26 | * `Blinker`_ provides support for :doc:`signals`.
27 |
28 | .. _Werkzeug: https://palletsprojects.com/p/werkzeug/
29 | .. _Jinja: https://palletsprojects.com/p/jinja/
30 | .. _MarkupSafe: https://palletsprojects.com/p/markupsafe/
31 | .. _ItsDangerous: https://palletsprojects.com/p/itsdangerous/
32 | .. _Click: https://palletsprojects.com/p/click/
33 | .. _Blinker: https://blinker.readthedocs.io/
34 |
35 |
36 | Optional dependencies
37 | ~~~~~~~~~~~~~~~~~~~~~
38 |
39 | These distributions will not be installed automatically. Flask will detect and
40 | use them if you install them.
41 |
42 | * `python-dotenv`_ enables support for :ref:`dotenv` when running ``flask``
43 | commands.
44 | * `Watchdog`_ provides a faster, more efficient reloader for the development
45 | server.
46 |
47 | .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
48 | .. _watchdog: https://pythonhosted.org/watchdog/
49 |
50 |
51 | greenlet
52 | ~~~~~~~~
53 |
54 | You may choose to use gevent or eventlet with your application. In this
55 | case, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
56 | required.
57 |
58 | These are not minimum supported versions, they only indicate the first
59 | versions that added necessary features. You should use the latest
60 | versions of each.
61 |
62 |
63 | Virtual environments
64 | --------------------
65 |
66 | Use a virtual environment to manage the dependencies for your project, both in
67 | development and in production.
68 |
69 | What problem does a virtual environment solve? The more Python projects you
70 | have, the more likely it is that you need to work with different versions of
71 | Python libraries, or even Python itself. Newer versions of libraries for one
72 | project can break compatibility in another project.
73 |
74 | Virtual environments are independent groups of Python libraries, one for each
75 | project. Packages installed for one project will not affect other projects or
76 | the operating system's packages.
77 |
78 | Python comes bundled with the :mod:`venv` module to create virtual
79 | environments.
80 |
81 |
82 | .. _install-create-env:
83 |
84 | Create an environment
85 | ~~~~~~~~~~~~~~~~~~~~~
86 |
87 | Create a project folder and a :file:`.venv` folder within:
88 |
89 | .. tabs::
90 |
91 | .. group-tab:: macOS/Linux
92 |
93 | .. code-block:: text
94 |
95 | $ mkdir myproject
96 | $ cd myproject
97 | $ python3 -m venv .venv
98 |
99 | .. group-tab:: Windows
100 |
101 | .. code-block:: text
102 |
103 | > mkdir myproject
104 | > cd myproject
105 | > py -3 -m venv .venv
106 |
107 |
108 | .. _install-activate-env:
109 |
110 | Activate the environment
111 | ~~~~~~~~~~~~~~~~~~~~~~~~
112 |
113 | Before you work on your project, activate the corresponding environment:
114 |
115 | .. tabs::
116 |
117 | .. group-tab:: macOS/Linux
118 |
119 | .. code-block:: text
120 |
121 | $ . .venv/bin/activate
122 |
123 | .. group-tab:: Windows
124 |
125 | .. code-block:: text
126 |
127 | > .venv\Scripts\activate
128 |
129 | Your shell prompt will change to show the name of the activated
130 | environment.
131 |
132 |
133 | Install Flask
134 | -------------
135 |
136 | Within the activated environment, use the following command to install
137 | Flask:
138 |
139 | .. code-block:: sh
140 |
141 | $ pip install Flask
142 |
143 | Flask is now installed. Check out the :doc:`/quickstart` or go to the
144 | :doc:`Documentation Overview `.
145 |
--------------------------------------------------------------------------------
/docs/license.rst:
--------------------------------------------------------------------------------
1 | BSD-3-Clause License
2 | ====================
3 |
4 | .. literalinclude:: ../LICENSE.txt
5 | :language: text
6 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/patterns/appfactories.rst:
--------------------------------------------------------------------------------
1 | Application Factories
2 | =====================
3 |
4 | If you are already using packages and blueprints for your application
5 | (:doc:`/blueprints`) there are a couple of really nice ways to further improve
6 | the experience. A common pattern is creating the application object when
7 | the blueprint is imported. But if you move the creation of this object
8 | into a function, you can then create multiple instances of this app later.
9 |
10 | So why would you want to do this?
11 |
12 | 1. Testing. You can have instances of the application with different
13 | settings to test every case.
14 | 2. Multiple instances. Imagine you want to run different versions of the
15 | same application. Of course you could have multiple instances with
16 | different configs set up in your webserver, but if you use factories,
17 | you can have multiple instances of the same application running in the
18 | same application process which can be handy.
19 |
20 | So how would you then actually implement that?
21 |
22 | Basic Factories
23 | ---------------
24 |
25 | The idea is to set up the application in a function. Like this::
26 |
27 | def create_app(config_filename):
28 | app = Flask(__name__)
29 | app.config.from_pyfile(config_filename)
30 |
31 | from yourapplication.model import db
32 | db.init_app(app)
33 |
34 | from yourapplication.views.admin import admin
35 | from yourapplication.views.frontend import frontend
36 | app.register_blueprint(admin)
37 | app.register_blueprint(frontend)
38 |
39 | return app
40 |
41 | The downside is that you cannot use the application object in the blueprints
42 | at import time. You can however use it from within a request. How do you
43 | get access to the application with the config? Use
44 | :data:`~flask.current_app`::
45 |
46 | from flask import current_app, Blueprint, render_template
47 | admin = Blueprint('admin', __name__, url_prefix='/admin')
48 |
49 | @admin.route('/')
50 | def index():
51 | return render_template(current_app.config['INDEX_TEMPLATE'])
52 |
53 | Here we look up the name of a template in the config.
54 |
55 | Factories & Extensions
56 | ----------------------
57 |
58 | It's preferable to create your extensions and app factories so that the
59 | extension object does not initially get bound to the application.
60 |
61 | Using `Flask-SQLAlchemy `_,
62 | as an example, you should not do something along those lines::
63 |
64 | def create_app(config_filename):
65 | app = Flask(__name__)
66 | app.config.from_pyfile(config_filename)
67 |
68 | db = SQLAlchemy(app)
69 |
70 | But, rather, in model.py (or equivalent)::
71 |
72 | db = SQLAlchemy()
73 |
74 | and in your application.py (or equivalent)::
75 |
76 | def create_app(config_filename):
77 | app = Flask(__name__)
78 | app.config.from_pyfile(config_filename)
79 |
80 | from yourapplication.model import db
81 | db.init_app(app)
82 |
83 | Using this design pattern, no application-specific state is stored on the
84 | extension object, so one extension object can be used for multiple apps.
85 | For more information about the design of extensions refer to :doc:`/extensiondev`.
86 |
87 | Using Applications
88 | ------------------
89 |
90 | To run such an application, you can use the :command:`flask` command:
91 |
92 | .. code-block:: text
93 |
94 | $ flask --app hello run
95 |
96 | Flask will automatically detect the factory if it is named
97 | ``create_app`` or ``make_app`` in ``hello``. You can also pass arguments
98 | to the factory like this:
99 |
100 | .. code-block:: text
101 |
102 | $ flask --app 'hello:create_app(local_auth=True)' run
103 |
104 | Then the ``create_app`` factory in ``hello`` is called with the keyword
105 | argument ``local_auth=True``. See :doc:`/cli` for more detail.
106 |
107 | Factory Improvements
108 | --------------------
109 |
110 | The factory function above is not very clever, but you can improve it.
111 | The following changes are straightforward to implement:
112 |
113 | 1. Make it possible to pass in configuration values for unit tests so that
114 | you don't have to create config files on the filesystem.
115 | 2. Call a function from a blueprint when the application is setting up so
116 | that you have a place to modify attributes of the application (like
117 | hooking in before/after request handlers etc.)
118 | 3. Add in WSGI middlewares when the application is being created if necessary.
119 |
--------------------------------------------------------------------------------
/docs/patterns/caching.rst:
--------------------------------------------------------------------------------
1 | Caching
2 | =======
3 |
4 | When your application runs slow, throw some caches in. Well, at least
5 | it's the easiest way to speed up things. What does a cache do? Say you
6 | have a function that takes some time to complete but the results would
7 | still be good enough if they were 5 minutes old. So then the idea is that
8 | you actually put the result of that calculation into a cache for some
9 | time.
10 |
11 | Flask itself does not provide caching for you, but `Flask-Caching`_, an
12 | extension for Flask does. Flask-Caching supports various backends, and it is
13 | even possible to develop your own caching backend.
14 |
15 |
16 | .. _Flask-Caching: https://flask-caching.readthedocs.io/en/latest/
17 |
--------------------------------------------------------------------------------
/docs/patterns/deferredcallbacks.rst:
--------------------------------------------------------------------------------
1 | Deferred Request Callbacks
2 | ==========================
3 |
4 | One of the design principles of Flask is that response objects are created and
5 | passed down a chain of potential callbacks that can modify them or replace
6 | them. When the request handling starts, there is no response object yet. It is
7 | created as necessary either by a view function or by some other component in
8 | the system.
9 |
10 | What happens if you want to modify the response at a point where the response
11 | does not exist yet? A common example for that would be a
12 | :meth:`~flask.Flask.before_request` callback that wants to set a cookie on the
13 | response object.
14 |
15 | One way is to avoid the situation. Very often that is possible. For instance
16 | you can try to move that logic into a :meth:`~flask.Flask.after_request`
17 | callback instead. However, sometimes moving code there makes it
18 | more complicated or awkward to reason about.
19 |
20 | As an alternative, you can use :func:`~flask.after_this_request` to register
21 | callbacks that will execute after only the current request. This way you can
22 | defer code execution from anywhere in the application, based on the current
23 | request.
24 |
25 | At any time during a request, we can register a function to be called at the
26 | end of the request. For example you can remember the current language of the
27 | user in a cookie in a :meth:`~flask.Flask.before_request` callback::
28 |
29 | from flask import request, after_this_request
30 |
31 | @app.before_request
32 | def detect_user_language():
33 | language = request.cookies.get('user_lang')
34 |
35 | if language is None:
36 | language = guess_language_from_request()
37 |
38 | # when the response exists, set a cookie with the language
39 | @after_this_request
40 | def remember_language(response):
41 | response.set_cookie('user_lang', language)
42 | return response
43 |
44 | g.language = language
45 |
--------------------------------------------------------------------------------
/docs/patterns/favicon.rst:
--------------------------------------------------------------------------------
1 | Adding a favicon
2 | ================
3 |
4 | A "favicon" is an icon used by browsers for tabs and bookmarks. This helps
5 | to distinguish your website and to give it a unique brand.
6 |
7 | A common question is how to add a favicon to a Flask application. First, of
8 | course, you need an icon. It should be 16 × 16 pixels and in the ICO file
9 | format. This is not a requirement but a de-facto standard supported by all
10 | relevant browsers. Put the icon in your static directory as
11 | :file:`favicon.ico`.
12 |
13 | Now, to get browsers to find your icon, the correct way is to add a link
14 | tag in your HTML. So, for example:
15 |
16 | .. sourcecode:: html+jinja
17 |
18 |
19 |
20 | That's all you need for most browsers, however some really old ones do not
21 | support this standard. The old de-facto standard is to serve this file,
22 | with this name, at the website root. If your application is not mounted at
23 | the root path of the domain you either need to configure the web server to
24 | serve the icon at the root or if you can't do that you're out of luck. If
25 | however your application is the root you can simply route a redirect::
26 |
27 | app.add_url_rule(
28 | "/favicon.ico",
29 | endpoint="favicon",
30 | redirect_to=url_for("static", filename="favicon.ico"),
31 | )
32 |
33 | If you want to save the extra redirect request you can also write a view
34 | using :func:`~flask.send_from_directory`::
35 |
36 | import os
37 | from flask import send_from_directory
38 |
39 | @app.route('/favicon.ico')
40 | def favicon():
41 | return send_from_directory(os.path.join(app.root_path, 'static'),
42 | 'favicon.ico', mimetype='image/vnd.microsoft.icon')
43 |
44 | We can leave out the explicit mimetype and it will be guessed, but we may
45 | as well specify it to avoid the extra guessing, as it will always be the
46 | same.
47 |
48 | The above will serve the icon via your application and if possible it's
49 | better to configure your dedicated web server to serve it; refer to the
50 | web server's documentation.
51 |
52 | See also
53 | --------
54 |
55 | * The `Favicon `_ article on
56 | Wikipedia
57 |
--------------------------------------------------------------------------------
/docs/patterns/index.rst:
--------------------------------------------------------------------------------
1 | Patterns for Flask
2 | ==================
3 |
4 | Certain features and interactions are common enough that you will find
5 | them in most web applications. For example, many applications use a
6 | relational database and user authentication. They will open a database
7 | connection at the beginning of the request and get the information for
8 | the logged in user. At the end of the request, the database connection
9 | is closed.
10 |
11 | These types of patterns may be a bit outside the scope of Flask itself,
12 | but Flask makes it easy to implement them. Some common patterns are
13 | collected in the following pages.
14 |
15 | .. toctree::
16 | :maxdepth: 2
17 |
18 | packages
19 | appfactories
20 | appdispatch
21 | urlprocessors
22 | sqlite3
23 | sqlalchemy
24 | fileuploads
25 | caching
26 | viewdecorators
27 | wtforms
28 | templateinheritance
29 | flashing
30 | javascript
31 | lazyloading
32 | mongoengine
33 | favicon
34 | streaming
35 | deferredcallbacks
36 | methodoverrides
37 | requestchecksum
38 | celery
39 | subclassing
40 | singlepageapplications
41 |
--------------------------------------------------------------------------------
/docs/patterns/jquery.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | AJAX with jQuery
4 | ================
5 |
6 | Obsolete, see :doc:`/patterns/javascript` instead.
7 |
--------------------------------------------------------------------------------
/docs/patterns/lazyloading.rst:
--------------------------------------------------------------------------------
1 | Lazily Loading Views
2 | ====================
3 |
4 | Flask is usually used with the decorators. Decorators are simple and you
5 | have the URL right next to the function that is called for that specific
6 | URL. However there is a downside to this approach: it means all your code
7 | that uses decorators has to be imported upfront or Flask will never
8 | actually find your function.
9 |
10 | This can be a problem if your application has to import quick. It might
11 | have to do that on systems like Google's App Engine or other systems. So
12 | if you suddenly notice that your application outgrows this approach you
13 | can fall back to a centralized URL mapping.
14 |
15 | The system that enables having a central URL map is the
16 | :meth:`~flask.Flask.add_url_rule` function. Instead of using decorators,
17 | you have a file that sets up the application with all URLs.
18 |
19 | Converting to Centralized URL Map
20 | ---------------------------------
21 |
22 | Imagine the current application looks somewhat like this::
23 |
24 | from flask import Flask
25 | app = Flask(__name__)
26 |
27 | @app.route('/')
28 | def index():
29 | pass
30 |
31 | @app.route('/user/')
32 | def user(username):
33 | pass
34 |
35 | Then, with the centralized approach you would have one file with the views
36 | (:file:`views.py`) but without any decorator::
37 |
38 | def index():
39 | pass
40 |
41 | def user(username):
42 | pass
43 |
44 | And then a file that sets up an application which maps the functions to
45 | URLs::
46 |
47 | from flask import Flask
48 | from yourapplication import views
49 | app = Flask(__name__)
50 | app.add_url_rule('/', view_func=views.index)
51 | app.add_url_rule('/user/', view_func=views.user)
52 |
53 | Loading Late
54 | ------------
55 |
56 | So far we only split up the views and the routing, but the module is still
57 | loaded upfront. The trick is to actually load the view function as needed.
58 | This can be accomplished with a helper class that behaves just like a
59 | function but internally imports the real function on first use::
60 |
61 | from werkzeug.utils import import_string, cached_property
62 |
63 | class LazyView(object):
64 |
65 | def __init__(self, import_name):
66 | self.__module__, self.__name__ = import_name.rsplit('.', 1)
67 | self.import_name = import_name
68 |
69 | @cached_property
70 | def view(self):
71 | return import_string(self.import_name)
72 |
73 | def __call__(self, *args, **kwargs):
74 | return self.view(*args, **kwargs)
75 |
76 | What's important here is is that `__module__` and `__name__` are properly
77 | set. This is used by Flask internally to figure out how to name the
78 | URL rules in case you don't provide a name for the rule yourself.
79 |
80 | Then you can define your central place to combine the views like this::
81 |
82 | from flask import Flask
83 | from yourapplication.helpers import LazyView
84 | app = Flask(__name__)
85 | app.add_url_rule('/',
86 | view_func=LazyView('yourapplication.views.index'))
87 | app.add_url_rule('/user/',
88 | view_func=LazyView('yourapplication.views.user'))
89 |
90 | You can further optimize this in terms of amount of keystrokes needed to
91 | write this by having a function that calls into
92 | :meth:`~flask.Flask.add_url_rule` by prefixing a string with the project
93 | name and a dot, and by wrapping `view_func` in a `LazyView` as needed. ::
94 |
95 | def url(import_name, url_rules=[], **options):
96 | view = LazyView(f"yourapplication.{import_name}")
97 | for url_rule in url_rules:
98 | app.add_url_rule(url_rule, view_func=view, **options)
99 |
100 | # add a single route to the index view
101 | url('views.index', ['/'])
102 |
103 | # add two routes to a single function endpoint
104 | url_rules = ['/user/','/user/']
105 | url('views.user', url_rules)
106 |
107 | One thing to keep in mind is that before and after request handlers have
108 | to be in a file that is imported upfront to work properly on the first
109 | request. The same goes for any kind of remaining decorator.
110 |
--------------------------------------------------------------------------------
/docs/patterns/methodoverrides.rst:
--------------------------------------------------------------------------------
1 | Adding HTTP Method Overrides
2 | ============================
3 |
4 | Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP
5 | methods (such as PATCH). In that case it's possible to "proxy" HTTP
6 | methods through another HTTP method in total violation of the protocol.
7 |
8 | The way this works is by letting the client do an HTTP POST request and
9 | set the ``X-HTTP-Method-Override`` header. Then the method is replaced
10 | with the header value before being passed to Flask.
11 |
12 | This can be accomplished with an HTTP middleware::
13 |
14 | class HTTPMethodOverrideMiddleware(object):
15 | allowed_methods = frozenset([
16 | 'GET',
17 | 'HEAD',
18 | 'POST',
19 | 'DELETE',
20 | 'PUT',
21 | 'PATCH',
22 | 'OPTIONS'
23 | ])
24 | bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE'])
25 |
26 | def __init__(self, app):
27 | self.app = app
28 |
29 | def __call__(self, environ, start_response):
30 | method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper()
31 | if method in self.allowed_methods:
32 | environ['REQUEST_METHOD'] = method
33 | if method in self.bodyless_methods:
34 | environ['CONTENT_LENGTH'] = '0'
35 | return self.app(environ, start_response)
36 |
37 | To use this with Flask, wrap the app object with the middleware::
38 |
39 | from flask import Flask
40 |
41 | app = Flask(__name__)
42 | app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app)
43 |
--------------------------------------------------------------------------------
/docs/patterns/mongoengine.rst:
--------------------------------------------------------------------------------
1 | MongoDB with MongoEngine
2 | ========================
3 |
4 | Using a document database like MongoDB is a common alternative to
5 | relational SQL databases. This pattern shows how to use
6 | `MongoEngine`_, a document mapper library, to integrate with MongoDB.
7 |
8 | A running MongoDB server and `Flask-MongoEngine`_ are required. ::
9 |
10 | pip install flask-mongoengine
11 |
12 | .. _MongoEngine: http://mongoengine.org
13 | .. _Flask-MongoEngine: https://flask-mongoengine.readthedocs.io
14 |
15 |
16 | Configuration
17 | -------------
18 |
19 | Basic setup can be done by defining ``MONGODB_SETTINGS`` on
20 | ``app.config`` and creating a ``MongoEngine`` instance. ::
21 |
22 | from flask import Flask
23 | from flask_mongoengine import MongoEngine
24 |
25 | app = Flask(__name__)
26 | app.config['MONGODB_SETTINGS'] = {
27 | "db": "myapp",
28 | }
29 | db = MongoEngine(app)
30 |
31 |
32 | Mapping Documents
33 | -----------------
34 |
35 | To declare a model that represents a Mongo document, create a class that
36 | inherits from ``Document`` and declare each of the fields. ::
37 |
38 | import mongoengine as me
39 |
40 | class Movie(me.Document):
41 | title = me.StringField(required=True)
42 | year = me.IntField()
43 | rated = me.StringField()
44 | director = me.StringField()
45 | actors = me.ListField()
46 |
47 | If the document has nested fields, use ``EmbeddedDocument`` to
48 | defined the fields of the embedded document and
49 | ``EmbeddedDocumentField`` to declare it on the parent document. ::
50 |
51 | class Imdb(me.EmbeddedDocument):
52 | imdb_id = me.StringField()
53 | rating = me.DecimalField()
54 | votes = me.IntField()
55 |
56 | class Movie(me.Document):
57 | ...
58 | imdb = me.EmbeddedDocumentField(Imdb)
59 |
60 |
61 | Creating Data
62 | -------------
63 |
64 | Instantiate your document class with keyword arguments for the fields.
65 | You can also assign values to the field attributes after instantiation.
66 | Then call ``doc.save()``. ::
67 |
68 | bttf = Movie(title="Back To The Future", year=1985)
69 | bttf.actors = [
70 | "Michael J. Fox",
71 | "Christopher Lloyd"
72 | ]
73 | bttf.imdb = Imdb(imdb_id="tt0088763", rating=8.5)
74 | bttf.save()
75 |
76 |
77 | Queries
78 | -------
79 |
80 | Use the class ``objects`` attribute to make queries. A keyword argument
81 | looks for an equal value on the field. ::
82 |
83 | bttf = Movie.objects(title="Back To The Future").get_or_404()
84 |
85 | Query operators may be used by concatenating them with the field name
86 | using a double-underscore. ``objects``, and queries returned by
87 | calling it, are iterable. ::
88 |
89 | some_theron_movie = Movie.objects(actors__in=["Charlize Theron"]).first()
90 |
91 | for recents in Movie.objects(year__gte=2017):
92 | print(recents.title)
93 |
94 |
95 | Documentation
96 | -------------
97 |
98 | There are many more ways to define and query documents with MongoEngine.
99 | For more information, check out the `official documentation
100 | `_.
101 |
102 | Flask-MongoEngine adds helpful utilities on top of MongoEngine. Check
103 | out their `documentation `_ as well.
104 |
--------------------------------------------------------------------------------
/docs/patterns/requestchecksum.rst:
--------------------------------------------------------------------------------
1 | Request Content Checksums
2 | =========================
3 |
4 | Various pieces of code can consume the request data and preprocess it.
5 | For instance JSON data ends up on the request object already read and
6 | processed, form data ends up there as well but goes through a different
7 | code path. This seems inconvenient when you want to calculate the
8 | checksum of the incoming request data. This is necessary sometimes for
9 | some APIs.
10 |
11 | Fortunately this is however very simple to change by wrapping the input
12 | stream.
13 |
14 | The following example calculates the SHA1 checksum of the incoming data as
15 | it gets read and stores it in the WSGI environment::
16 |
17 | import hashlib
18 |
19 | class ChecksumCalcStream(object):
20 |
21 | def __init__(self, stream):
22 | self._stream = stream
23 | self._hash = hashlib.sha1()
24 |
25 | def read(self, bytes):
26 | rv = self._stream.read(bytes)
27 | self._hash.update(rv)
28 | return rv
29 |
30 | def readline(self, size_hint):
31 | rv = self._stream.readline(size_hint)
32 | self._hash.update(rv)
33 | return rv
34 |
35 | def generate_checksum(request):
36 | env = request.environ
37 | stream = ChecksumCalcStream(env['wsgi.input'])
38 | env['wsgi.input'] = stream
39 | return stream._hash
40 |
41 | To use this, all you need to do is to hook the calculating stream in
42 | before the request starts consuming data. (Eg: be careful accessing
43 | ``request.form`` or anything of that nature. ``before_request_handlers``
44 | for instance should be careful not to access it).
45 |
46 | Example usage::
47 |
48 | @app.route('/special-api', methods=['POST'])
49 | def special_api():
50 | hash = generate_checksum(request)
51 | # Accessing this parses the input stream
52 | files = request.files
53 | # At this point the hash is fully constructed.
54 | checksum = hash.hexdigest()
55 | return f"Hash was: {checksum}"
56 |
--------------------------------------------------------------------------------
/docs/patterns/singlepageapplications.rst:
--------------------------------------------------------------------------------
1 | Single-Page Applications
2 | ========================
3 |
4 | Flask can be used to serve Single-Page Applications (SPA) by placing static
5 | files produced by your frontend framework in a subfolder inside of your
6 | project. You will also need to create a catch-all endpoint that routes all
7 | requests to your SPA.
8 |
9 | The following example demonstrates how to serve an SPA along with an API::
10 |
11 | from flask import Flask, jsonify
12 |
13 | app = Flask(__name__, static_folder='app', static_url_path="/app")
14 |
15 |
16 | @app.route("/heartbeat")
17 | def heartbeat():
18 | return jsonify({"status": "healthy"})
19 |
20 |
21 | @app.route('/', defaults={'path': ''})
22 | @app.route('/')
23 | def catch_all(path):
24 | return app.send_static_file("index.html")
25 |
--------------------------------------------------------------------------------
/docs/patterns/streaming.rst:
--------------------------------------------------------------------------------
1 | Streaming Contents
2 | ==================
3 |
4 | Sometimes you want to send an enormous amount of data to the client, much
5 | more than you want to keep in memory. When you are generating the data on
6 | the fly though, how do you send that back to the client without the
7 | roundtrip to the filesystem?
8 |
9 | The answer is by using generators and direct responses.
10 |
11 | Basic Usage
12 | -----------
13 |
14 | This is a basic view function that generates a lot of CSV data on the fly.
15 | The trick is to have an inner function that uses a generator to generate
16 | data and to then invoke that function and pass it to a response object::
17 |
18 | @app.route('/large.csv')
19 | def generate_large_csv():
20 | def generate():
21 | for row in iter_all_rows():
22 | yield f"{','.join(row)}\n"
23 | return generate(), {"Content-Type": "text/csv"}
24 |
25 | Each ``yield`` expression is directly sent to the browser. Note though
26 | that some WSGI middlewares might break streaming, so be careful there in
27 | debug environments with profilers and other things you might have enabled.
28 |
29 | Streaming from Templates
30 | ------------------------
31 |
32 | The Jinja2 template engine supports rendering a template piece by
33 | piece, returning an iterator of strings. Flask provides the
34 | :func:`~flask.stream_template` and :func:`~flask.stream_template_string`
35 | functions to make this easier to use.
36 |
37 | .. code-block:: python
38 |
39 | from flask import stream_template
40 |
41 | @app.get("/timeline")
42 | def timeline():
43 | return stream_template("timeline.html")
44 |
45 | The parts yielded by the render stream tend to match statement blocks in
46 | the template.
47 |
48 |
49 | Streaming with Context
50 | ----------------------
51 |
52 | The :data:`~flask.request` will not be active while the generator is
53 | running, because the view has already returned at that point. If you try
54 | to access ``request``, you'll get a ``RuntimeError``.
55 |
56 | If your generator function relies on data in ``request``, use the
57 | :func:`~flask.stream_with_context` wrapper. This will keep the request
58 | context active during the generator.
59 |
60 | .. code-block:: python
61 |
62 | from flask import stream_with_context, request
63 | from markupsafe import escape
64 |
65 | @app.route('/stream')
66 | def streamed_response():
67 | def generate():
68 | yield '
'
71 | return stream_with_context(generate())
72 |
73 | It can also be used as a decorator.
74 |
75 | .. code-block:: python
76 |
77 | @stream_with_context
78 | def generate():
79 | ...
80 |
81 | return generate()
82 |
83 | The :func:`~flask.stream_template` and
84 | :func:`~flask.stream_template_string` functions automatically
85 | use :func:`~flask.stream_with_context` if a request is active.
86 |
--------------------------------------------------------------------------------
/docs/patterns/subclassing.rst:
--------------------------------------------------------------------------------
1 | Subclassing Flask
2 | =================
3 |
4 | The :class:`~flask.Flask` class is designed for subclassing.
5 |
6 | For example, you may want to override how request parameters are handled to preserve their order::
7 |
8 | from flask import Flask, Request
9 | from werkzeug.datastructures import ImmutableOrderedMultiDict
10 | class MyRequest(Request):
11 | """Request subclass to override request parameter storage"""
12 | parameter_storage_class = ImmutableOrderedMultiDict
13 | class MyFlask(Flask):
14 | """Flask subclass using the custom request class"""
15 | request_class = MyRequest
16 |
17 | This is the recommended approach for overriding or augmenting Flask's internal functionality.
18 |
--------------------------------------------------------------------------------
/docs/patterns/templateinheritance.rst:
--------------------------------------------------------------------------------
1 | Template Inheritance
2 | ====================
3 |
4 | The most powerful part of Jinja is template inheritance. Template inheritance
5 | allows you to build a base "skeleton" template that contains all the common
6 | elements of your site and defines **blocks** that child templates can override.
7 |
8 | Sounds complicated but is very basic. It's easiest to understand it by starting
9 | with an example.
10 |
11 |
12 | Base Template
13 | -------------
14 |
15 | This template, which we'll call :file:`layout.html`, defines a simple HTML skeleton
16 | document that you might use for a simple two-column page. It's the job of
17 | "child" templates to fill the empty blocks with content:
18 |
19 | .. sourcecode:: html+jinja
20 |
21 |
22 |
23 |
24 | {% block head %}
25 |
26 | {% block title %}{% endblock %} - My Webpage
27 | {% endblock %}
28 |
29 |
30 |
{% block content %}{% endblock %}
31 |
36 |
37 |
38 |
39 | In this example, the ``{% block %}`` tags define four blocks that child templates
40 | can fill in. All the `block` tag does is tell the template engine that a
41 | child template may override those portions of the template.
42 |
43 | Child Template
44 | --------------
45 |
46 | A child template might look like this:
47 |
48 | .. sourcecode:: html+jinja
49 |
50 | {% extends "layout.html" %}
51 | {% block title %}Index{% endblock %}
52 | {% block head %}
53 | {{ super() }}
54 |
57 | {% endblock %}
58 | {% block content %}
59 |
Index
60 |
61 | Welcome on my awesome homepage.
62 | {% endblock %}
63 |
64 | The ``{% extends %}`` tag is the key here. It tells the template engine that
65 | this template "extends" another template. When the template system evaluates
66 | this template, first it locates the parent. The extends tag must be the
67 | first tag in the template. To render the contents of a block defined in
68 | the parent template, use ``{{ super() }}``.
69 |
--------------------------------------------------------------------------------
/docs/server.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: flask
2 |
3 | Development Server
4 | ==================
5 |
6 | Flask provides a ``run`` command to run the application with a development server. In
7 | debug mode, this server provides an interactive debugger and will reload when code is
8 | changed.
9 |
10 | .. warning::
11 |
12 | Do not use the development server when deploying to production. It
13 | is intended for use only during local development. It is not
14 | designed to be particularly efficient, stable, or secure.
15 |
16 | See :doc:`/deploying/index` for deployment options.
17 |
18 | Command Line
19 | ------------
20 |
21 | The ``flask run`` CLI command is the recommended way to run the development server. Use
22 | the ``--app`` option to point to your application, and the ``--debug`` option to enable
23 | debug mode.
24 |
25 | .. code-block:: text
26 |
27 | $ flask --app hello run --debug
28 |
29 | This enables debug mode, including the interactive debugger and reloader, and then
30 | starts the server on http://localhost:5000/. Use ``flask run --help`` to see the
31 | available options, and :doc:`/cli` for detailed instructions about configuring and using
32 | the CLI.
33 |
34 |
35 | .. _address-already-in-use:
36 |
37 | Address already in use
38 | ~~~~~~~~~~~~~~~~~~~~~~
39 |
40 | If another program is already using port 5000, you'll see an ``OSError``
41 | when the server tries to start. It may have one of the following
42 | messages:
43 |
44 | - ``OSError: [Errno 98] Address already in use``
45 | - ``OSError: [WinError 10013] An attempt was made to access a socket
46 | in a way forbidden by its access permissions``
47 |
48 | Either identify and stop the other program, or use
49 | ``flask run --port 5001`` to pick a different port.
50 |
51 | You can use ``netstat`` or ``lsof`` to identify what process id is using
52 | a port, then use other operating system tools stop that process. The
53 | following example shows that process id 6847 is using port 5000.
54 |
55 | .. tabs::
56 |
57 | .. tab:: ``netstat`` (Linux)
58 |
59 | .. code-block:: text
60 |
61 | $ netstat -nlp | grep 5000
62 | tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN 6847/python
63 |
64 | .. tab:: ``lsof`` (macOS / Linux)
65 |
66 | .. code-block:: text
67 |
68 | $ lsof -P -i :5000
69 | Python 6847 IPv4 TCP localhost:5000 (LISTEN)
70 |
71 | .. tab:: ``netstat`` (Windows)
72 |
73 | .. code-block:: text
74 |
75 | > netstat -ano | findstr 5000
76 | TCP 127.0.0.1:5000 0.0.0.0:0 LISTENING 6847
77 |
78 | macOS Monterey and later automatically starts a service that uses port
79 | 5000. You can choose to disable this service instead of using a different port by
80 | searching for "AirPlay Receiver" in System Preferences and toggling it off.
81 |
82 |
83 | Deferred Errors on Reload
84 | ~~~~~~~~~~~~~~~~~~~~~~~~~
85 |
86 | When using the ``flask run`` command with the reloader, the server will
87 | continue to run even if you introduce syntax errors or other
88 | initialization errors into the code. Accessing the site will show the
89 | interactive debugger for the error, rather than crashing the server.
90 |
91 | If a syntax error is already present when calling ``flask run``, it will
92 | fail immediately and show the traceback rather than waiting until the
93 | site is accessed. This is intended to make errors more visible initially
94 | while still allowing the server to handle errors on reload.
95 |
96 |
97 | In Code
98 | -------
99 |
100 | The development server can also be started from Python with the :meth:`Flask.run`
101 | method. This method takes arguments similar to the CLI options to control the server.
102 | The main difference from the CLI command is that the server will crash if there are
103 | errors when reloading. ``debug=True`` can be passed to enable debug mode.
104 |
105 | Place the call in a main block, otherwise it will interfere when trying to import and
106 | run the application with a production server later.
107 |
108 | .. code-block:: python
109 |
110 | if __name__ == "__main__":
111 | app.run(debug=True)
112 |
113 | .. code-block:: text
114 |
115 | $ python hello.py
116 |
--------------------------------------------------------------------------------
/docs/shell.rst:
--------------------------------------------------------------------------------
1 | Working with the Shell
2 | ======================
3 |
4 | .. versionadded:: 0.3
5 |
6 | One of the reasons everybody loves Python is the interactive shell. It
7 | basically allows you to execute Python commands in real time and
8 | immediately get results back. Flask itself does not come with an
9 | interactive shell, because it does not require any specific setup upfront,
10 | just import your application and start playing around.
11 |
12 | There are however some handy helpers to make playing around in the shell a
13 | more pleasant experience. The main issue with interactive console
14 | sessions is that you're not triggering a request like a browser does which
15 | means that :data:`~flask.g`, :data:`~flask.request` and others are not
16 | available. But the code you want to test might depend on them, so what
17 | can you do?
18 |
19 | This is where some helper functions come in handy. Keep in mind however
20 | that these functions are not only there for interactive shell usage, but
21 | also for unit testing and other situations that require a faked request
22 | context.
23 |
24 | Generally it's recommended that you read :doc:`reqcontext` first.
25 |
26 | Command Line Interface
27 | ----------------------
28 |
29 | Starting with Flask 0.11 the recommended way to work with the shell is the
30 | ``flask shell`` command which does a lot of this automatically for you.
31 | For instance the shell is automatically initialized with a loaded
32 | application context.
33 |
34 | For more information see :doc:`/cli`.
35 |
36 | Creating a Request Context
37 | --------------------------
38 |
39 | The easiest way to create a proper request context from the shell is by
40 | using the :attr:`~flask.Flask.test_request_context` method which creates
41 | us a :class:`~flask.ctx.RequestContext`:
42 |
43 | >>> ctx = app.test_request_context()
44 |
45 | Normally you would use the ``with`` statement to make this request object
46 | active, but in the shell it's easier to use the
47 | :meth:`~flask.ctx.RequestContext.push` and
48 | :meth:`~flask.ctx.RequestContext.pop` methods by hand:
49 |
50 | >>> ctx.push()
51 |
52 | From that point onwards you can work with the request object until you
53 | call `pop`:
54 |
55 | >>> ctx.pop()
56 |
57 | Firing Before/After Request
58 | ---------------------------
59 |
60 | By just creating a request context, you still don't have run the code that
61 | is normally run before a request. This might result in your database
62 | being unavailable if you are connecting to the database in a
63 | before-request callback or the current user not being stored on the
64 | :data:`~flask.g` object etc.
65 |
66 | This however can easily be done yourself. Just call
67 | :meth:`~flask.Flask.preprocess_request`:
68 |
69 | >>> ctx = app.test_request_context()
70 | >>> ctx.push()
71 | >>> app.preprocess_request()
72 |
73 | Keep in mind that the :meth:`~flask.Flask.preprocess_request` function
74 | might return a response object, in that case just ignore it.
75 |
76 | To shutdown a request, you need to trick a bit before the after request
77 | functions (triggered by :meth:`~flask.Flask.process_response`) operate on
78 | a response object:
79 |
80 | >>> app.process_response(app.response_class())
81 |
82 | >>> ctx.pop()
83 |
84 | The functions registered as :meth:`~flask.Flask.teardown_request` are
85 | automatically called when the context is popped. So this is the perfect
86 | place to automatically tear down resources that were needed by the request
87 | context (such as database connections).
88 |
89 |
90 | Further Improving the Shell Experience
91 | --------------------------------------
92 |
93 | If you like the idea of experimenting in a shell, create yourself a module
94 | with stuff you want to star import into your interactive session. There
95 | you could also define some more helper methods for common things such as
96 | initializing the database, dropping tables etc.
97 |
98 | Just put them into a module (like `shelltools`) and import from there:
99 |
100 | >>> from shelltools import *
101 |
--------------------------------------------------------------------------------
/docs/tutorial/deploy.rst:
--------------------------------------------------------------------------------
1 | Deploy to Production
2 | ====================
3 |
4 | This part of the tutorial assumes you have a server that you want to
5 | deploy your application to. It gives an overview of how to create the
6 | distribution file and install it, but won't go into specifics about
7 | what server or software to use. You can set up a new environment on your
8 | development computer to try out the instructions below, but probably
9 | shouldn't use it for hosting a real public application. See
10 | :doc:`/deploying/index` for a list of many different ways to host your
11 | application.
12 |
13 |
14 | Build and Install
15 | -----------------
16 |
17 | When you want to deploy your application elsewhere, you build a *wheel*
18 | (``.whl``) file. Install and use the ``build`` tool to do this.
19 |
20 | .. code-block:: none
21 |
22 | $ pip install build
23 | $ python -m build --wheel
24 |
25 | You can find the file in ``dist/flaskr-1.0.0-py3-none-any.whl``. The
26 | file name is in the format of {project name}-{version}-{python tag}
27 | -{abi tag}-{platform tag}.
28 |
29 | Copy this file to another machine,
30 | :ref:`set up a new virtualenv `, then install the
31 | file with ``pip``.
32 |
33 | .. code-block:: none
34 |
35 | $ pip install flaskr-1.0.0-py3-none-any.whl
36 |
37 | Pip will install your project along with its dependencies.
38 |
39 | Since this is a different machine, you need to run ``init-db`` again to
40 | create the database in the instance folder.
41 |
42 | .. code-block:: text
43 |
44 | $ flask --app flaskr init-db
45 |
46 | When Flask detects that it's installed (not in editable mode), it uses
47 | a different directory for the instance folder. You can find it at
48 | ``.venv/var/flaskr-instance`` instead.
49 |
50 |
51 | Configure the Secret Key
52 | ------------------------
53 |
54 | In the beginning of the tutorial that you gave a default value for
55 | :data:`SECRET_KEY`. This should be changed to some random bytes in
56 | production. Otherwise, attackers could use the public ``'dev'`` key to
57 | modify the session cookie, or anything else that uses the secret key.
58 |
59 | You can use the following command to output a random secret key:
60 |
61 | .. code-block:: none
62 |
63 | $ python -c 'import secrets; print(secrets.token_hex())'
64 |
65 | '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
66 |
67 | Create the ``config.py`` file in the instance folder, which the factory
68 | will read from if it exists. Copy the generated value into it.
69 |
70 | .. code-block:: python
71 | :caption: ``.venv/var/flaskr-instance/config.py``
72 |
73 | SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
74 |
75 | You can also set any other necessary configuration here, although
76 | ``SECRET_KEY`` is the only one needed for Flaskr.
77 |
78 |
79 | Run with a Production Server
80 | ----------------------------
81 |
82 | When running publicly rather than in development, you should not use the
83 | built-in development server (``flask run``). The development server is
84 | provided by Werkzeug for convenience, but is not designed to be
85 | particularly efficient, stable, or secure.
86 |
87 | Instead, use a production WSGI server. For example, to use `Waitress`_,
88 | first install it in the virtual environment:
89 |
90 | .. code-block:: none
91 |
92 | $ pip install waitress
93 |
94 | You need to tell Waitress about your application, but it doesn't use
95 | ``--app`` like ``flask run`` does. You need to tell it to import and
96 | call the application factory to get an application object.
97 |
98 | .. code-block:: none
99 |
100 | $ waitress-serve --call 'flaskr:create_app'
101 |
102 | Serving on http://0.0.0.0:8080
103 |
104 | See :doc:`/deploying/index` for a list of many different ways to host
105 | your application. Waitress is just an example, chosen for the tutorial
106 | because it supports both Windows and Linux. There are many more WSGI
107 | servers and deployment options that you may choose for your project.
108 |
109 | .. _Waitress: https://docs.pylonsproject.org/projects/waitress/en/stable/
110 |
111 | Continue to :doc:`next`.
112 |
--------------------------------------------------------------------------------
/docs/tutorial/flaskr_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/tutorial/flaskr_edit.png
--------------------------------------------------------------------------------
/docs/tutorial/flaskr_index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/tutorial/flaskr_index.png
--------------------------------------------------------------------------------
/docs/tutorial/flaskr_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallets/flask/a5f9742398c9429ef84ac8a57b0f3eb418394d9e/docs/tutorial/flaskr_login.png
--------------------------------------------------------------------------------
/docs/tutorial/index.rst:
--------------------------------------------------------------------------------
1 | Tutorial
2 | ========
3 |
4 | .. toctree::
5 | :caption: Contents:
6 | :maxdepth: 1
7 |
8 | layout
9 | factory
10 | database
11 | views
12 | templates
13 | static
14 | blog
15 | install
16 | tests
17 | deploy
18 | next
19 |
20 | This tutorial will walk you through creating a basic blog application
21 | called Flaskr. Users will be able to register, log in, create posts,
22 | and edit or delete their own posts. You will be able to package and
23 | install the application on other computers.
24 |
25 | .. image:: flaskr_index.png
26 | :align: center
27 | :class: screenshot
28 | :alt: screenshot of index page
29 |
30 | It's assumed that you're already familiar with Python. The `official
31 | tutorial`_ in the Python docs is a great way to learn or review first.
32 |
33 | .. _official tutorial: https://docs.python.org/3/tutorial/
34 |
35 | While it's designed to give a good starting point, the tutorial doesn't
36 | cover all of Flask's features. Check out the :doc:`/quickstart` for an
37 | overview of what Flask can do, then dive into the docs to find out more.
38 | The tutorial only uses what's provided by Flask and Python. In another
39 | project, you might decide to use :doc:`/extensions` or other libraries
40 | to make some tasks simpler.
41 |
42 | .. image:: flaskr_login.png
43 | :align: center
44 | :class: screenshot
45 | :alt: screenshot of login page
46 |
47 | Flask is flexible. It doesn't require you to use any particular project
48 | or code layout. However, when first starting, it's helpful to use a more
49 | structured approach. This means that the tutorial will require a bit of
50 | boilerplate up front, but it's done to avoid many common pitfalls that
51 | new developers encounter, and it creates a project that's easy to expand
52 | on. Once you become more comfortable with Flask, you can step out of
53 | this structure and take full advantage of Flask's flexibility.
54 |
55 | .. image:: flaskr_edit.png
56 | :align: center
57 | :class: screenshot
58 | :alt: screenshot of edit page
59 |
60 | :gh:`The tutorial project is available as an example in the Flask
61 | repository `, if you want to compare your project
62 | with the final product as you follow the tutorial.
63 |
64 | Continue to :doc:`layout`.
65 |
--------------------------------------------------------------------------------
/docs/tutorial/install.rst:
--------------------------------------------------------------------------------
1 | Make the Project Installable
2 | ============================
3 |
4 | Making your project installable means that you can build a *wheel* file and install that
5 | in another environment, just like you installed Flask in your project's environment.
6 | This makes deploying your project the same as installing any other library, so you're
7 | using all the standard Python tools to manage everything.
8 |
9 | Installing also comes with other benefits that might not be obvious from
10 | the tutorial or as a new Python user, including:
11 |
12 | * Currently, Python and Flask understand how to use the ``flaskr``
13 | package only because you're running from your project's directory.
14 | Installing means you can import it no matter where you run from.
15 |
16 | * You can manage your project's dependencies just like other packages
17 | do, so ``pip install yourproject.whl`` installs them.
18 |
19 | * Test tools can isolate your test environment from your development
20 | environment.
21 |
22 | .. note::
23 | This is being introduced late in the tutorial, but in your future
24 | projects you should always start with this.
25 |
26 |
27 | Describe the Project
28 | --------------------
29 |
30 | The ``pyproject.toml`` file describes your project and how to build it.
31 |
32 | .. code-block:: toml
33 | :caption: ``pyproject.toml``
34 |
35 | [project]
36 | name = "flaskr"
37 | version = "1.0.0"
38 | description = "The basic blog app built in the Flask tutorial."
39 | dependencies = [
40 | "flask",
41 | ]
42 |
43 | [build-system]
44 | requires = ["flit_core<4"]
45 | build-backend = "flit_core.buildapi"
46 |
47 | See the official `Packaging tutorial `_ for more
48 | explanation of the files and options used.
49 |
50 | .. _packaging tutorial: https://packaging.python.org/tutorials/packaging-projects/
51 |
52 |
53 | Install the Project
54 | -------------------
55 |
56 | Use ``pip`` to install your project in the virtual environment.
57 |
58 | .. code-block:: none
59 |
60 | $ pip install -e .
61 |
62 | This tells pip to find ``pyproject.toml`` in the current directory and install the
63 | project in *editable* or *development* mode. Editable mode means that as you make
64 | changes to your local code, you'll only need to re-install if you change the metadata
65 | about the project, such as its dependencies.
66 |
67 | You can observe that the project is now installed with ``pip list``.
68 |
69 | .. code-block:: none
70 |
71 | $ pip list
72 |
73 | Package Version Location
74 | -------------- --------- ----------------------------------
75 | click 6.7
76 | Flask 1.0
77 | flaskr 1.0.0 /home/user/Projects/flask-tutorial
78 | itsdangerous 0.24
79 | Jinja2 2.10
80 | MarkupSafe 1.0
81 | pip 9.0.3
82 | Werkzeug 0.14.1
83 |
84 | Nothing changes from how you've been running your project so far.
85 | ``--app`` is still set to ``flaskr`` and ``flask run`` still runs
86 | the application, but you can call it from anywhere, not just the
87 | ``flask-tutorial`` directory.
88 |
89 | Continue to :doc:`tests`.
90 |
--------------------------------------------------------------------------------
/docs/tutorial/layout.rst:
--------------------------------------------------------------------------------
1 | Project Layout
2 | ==============
3 |
4 | Create a project directory and enter it:
5 |
6 | .. code-block:: none
7 |
8 | $ mkdir flask-tutorial
9 | $ cd flask-tutorial
10 |
11 | Then follow the :doc:`installation instructions ` to set
12 | up a Python virtual environment and install Flask for your project.
13 |
14 | The tutorial will assume you're working from the ``flask-tutorial``
15 | directory from now on. The file names at the top of each code block are
16 | relative to this directory.
17 |
18 | ----
19 |
20 | A Flask application can be as simple as a single file.
21 |
22 | .. code-block:: python
23 | :caption: ``hello.py``
24 |
25 | from flask import Flask
26 |
27 | app = Flask(__name__)
28 |
29 |
30 | @app.route('/')
31 | def hello():
32 | return 'Hello, World!'
33 |
34 | However, as a project gets bigger, it becomes overwhelming to keep all
35 | the code in one file. Python projects use *packages* to organize code
36 | into multiple modules that can be imported where needed, and the
37 | tutorial will do this as well.
38 |
39 | The project directory will contain:
40 |
41 | * ``flaskr/``, a Python package containing your application code and
42 | files.
43 | * ``tests/``, a directory containing test modules.
44 | * ``.venv/``, a Python virtual environment where Flask and other
45 | dependencies are installed.
46 | * Installation files telling Python how to install your project.
47 | * Version control config, such as `git`_. You should make a habit of
48 | using some type of version control for all your projects, no matter
49 | the size.
50 | * Any other project files you might add in the future.
51 |
52 | .. _git: https://git-scm.com/
53 |
54 | By the end, your project layout will look like this:
55 |
56 | .. code-block:: none
57 |
58 | /home/user/Projects/flask-tutorial
59 | ├── flaskr/
60 | │ ├── __init__.py
61 | │ ├── db.py
62 | │ ├── schema.sql
63 | │ ├── auth.py
64 | │ ├── blog.py
65 | │ ├── templates/
66 | │ │ ├── base.html
67 | │ │ ├── auth/
68 | │ │ │ ├── login.html
69 | │ │ │ └── register.html
70 | │ │ └── blog/
71 | │ │ ├── create.html
72 | │ │ ├── index.html
73 | │ │ └── update.html
74 | │ └── static/
75 | │ └── style.css
76 | ├── tests/
77 | │ ├── conftest.py
78 | │ ├── data.sql
79 | │ ├── test_factory.py
80 | │ ├── test_db.py
81 | │ ├── test_auth.py
82 | │ └── test_blog.py
83 | ├── .venv/
84 | ├── pyproject.toml
85 | └── MANIFEST.in
86 |
87 | If you're using version control, the following files that are generated
88 | while running your project should be ignored. There may be other files
89 | based on the editor you use. In general, ignore files that you didn't
90 | write. For example, with git:
91 |
92 | .. code-block:: none
93 | :caption: ``.gitignore``
94 |
95 | .venv/
96 |
97 | *.pyc
98 | __pycache__/
99 |
100 | instance/
101 |
102 | .pytest_cache/
103 | .coverage
104 | htmlcov/
105 |
106 | dist/
107 | build/
108 | *.egg-info/
109 |
110 | Continue to :doc:`factory`.
111 |
--------------------------------------------------------------------------------
/docs/tutorial/next.rst:
--------------------------------------------------------------------------------
1 | Keep Developing!
2 | ================
3 |
4 | You've learned about quite a few Flask and Python concepts throughout
5 | the tutorial. Go back and review the tutorial and compare your code with
6 | the steps you took to get there. Compare your project to the
7 | :gh:`example project `, which might look a bit
8 | different due to the step-by-step nature of the tutorial.
9 |
10 | There's a lot more to Flask than what you've seen so far. Even so,
11 | you're now equipped to start developing your own web applications. Check
12 | out the :doc:`/quickstart` for an overview of what Flask can do, then
13 | dive into the docs to keep learning. Flask uses `Jinja`_, `Click`_,
14 | `Werkzeug`_, and `ItsDangerous`_ behind the scenes, and they all have
15 | their own documentation too. You'll also be interested in
16 | :doc:`/extensions` which make tasks like working with the database or
17 | validating form data easier and more powerful.
18 |
19 | If you want to keep developing your Flaskr project, here are some ideas
20 | for what to try next:
21 |
22 | * A detail view to show a single post. Click a post's title to go to
23 | its page.
24 | * Like / unlike a post.
25 | * Comments.
26 | * Tags. Clicking a tag shows all the posts with that tag.
27 | * A search box that filters the index page by name.
28 | * Paged display. Only show 5 posts per page.
29 | * Upload an image to go along with a post.
30 | * Format posts using Markdown.
31 | * An RSS feed of new posts.
32 |
33 | Have fun and make awesome applications!
34 |
35 | .. _Jinja: https://palletsprojects.com/p/jinja/
36 | .. _Click: https://palletsprojects.com/p/click/
37 | .. _Werkzeug: https://palletsprojects.com/p/werkzeug/
38 | .. _ItsDangerous: https://palletsprojects.com/p/itsdangerous/
39 |
--------------------------------------------------------------------------------
/docs/tutorial/static.rst:
--------------------------------------------------------------------------------
1 | Static Files
2 | ============
3 |
4 | The authentication views and templates work, but they look very plain
5 | right now. Some `CSS`_ can be added to add style to the HTML layout you
6 | constructed. The style won't change, so it's a *static* file rather than
7 | a template.
8 |
9 | Flask automatically adds a ``static`` view that takes a path relative
10 | to the ``flaskr/static`` directory and serves it. The ``base.html``
11 | template already has a link to the ``style.css`` file:
12 |
13 | .. code-block:: html+jinja
14 |
15 | {{ url_for('static', filename='style.css') }}
16 |
17 | Besides CSS, other types of static files might be files with JavaScript
18 | functions, or a logo image. They are all placed under the
19 | ``flaskr/static`` directory and referenced with
20 | ``url_for('static', filename='...')``.
21 |
22 | This tutorial isn't focused on how to write CSS, so you can just copy
23 | the following into the ``flaskr/static/style.css`` file:
24 |
25 | .. code-block:: css
26 | :caption: ``flaskr/static/style.css``
27 |
28 | html { font-family: sans-serif; background: #eee; padding: 1rem; }
29 | body { max-width: 960px; margin: 0 auto; background: white; }
30 | h1 { font-family: serif; color: #377ba8; margin: 1rem 0; }
31 | a { color: #377ba8; }
32 | hr { border: none; border-top: 1px solid lightgray; }
33 | nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; }
34 | nav h1 { flex: auto; margin: 0; }
35 | nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; }
36 | nav ul { display: flex; list-style: none; margin: 0; padding: 0; }
37 | nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; }
38 | .content { padding: 0 1rem 1rem; }
39 | .content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; }
40 | .content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; }
41 | .flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; }
42 | .post > header { display: flex; align-items: flex-end; font-size: 0.85em; }
43 | .post > header > div:first-of-type { flex: auto; }
44 | .post > header h1 { font-size: 1.5em; margin-bottom: 0; }
45 | .post .about { color: slategray; font-style: italic; }
46 | .post .body { white-space: pre-line; }
47 | .content:last-child { margin-bottom: 0; }
48 | .content form { margin: 1em 0; display: flex; flex-direction: column; }
49 | .content label { font-weight: bold; margin-bottom: 0.5em; }
50 | .content input, .content textarea { margin-bottom: 1em; }
51 | .content textarea { min-height: 12em; resize: vertical; }
52 | input.danger { color: #cc2f2e; }
53 | input[type=submit] { align-self: start; min-width: 10em; }
54 |
55 | You can find a less compact version of ``style.css`` in the
56 | :gh:`example code `.
57 |
58 | Go to http://127.0.0.1:5000/auth/login and the page should look like the
59 | screenshot below.
60 |
61 | .. image:: flaskr_login.png
62 | :align: center
63 | :class: screenshot
64 | :alt: screenshot of login page
65 |
66 | You can read more about CSS from `Mozilla's documentation `_. If
67 | you change a static file, refresh the browser page. If the change
68 | doesn't show up, try clearing your browser's cache.
69 |
70 | .. _CSS: https://developer.mozilla.org/docs/Web/CSS
71 |
72 | Continue to :doc:`blog`.
73 |
--------------------------------------------------------------------------------
/examples/celery/README.md:
--------------------------------------------------------------------------------
1 | Background Tasks with Celery
2 | ============================
3 |
4 | This example shows how to configure Celery with Flask, how to set up an API for
5 | submitting tasks and polling results, and how to use that API with JavaScript. See
6 | [Flask's documentation about Celery](https://flask.palletsprojects.com/patterns/celery/).
7 |
8 | From this directory, create a virtualenv and install the application into it. Then run a
9 | Celery worker.
10 |
11 | ```shell
12 | $ python3 -m venv .venv
13 | $ . ./.venv/bin/activate
14 | $ pip install -r requirements.txt && pip install -e .
15 | $ celery -A make_celery worker --loglevel INFO
16 | ```
17 |
18 | In a separate terminal, activate the virtualenv and run the Flask development server.
19 |
20 | ```shell
21 | $ . ./.venv/bin/activate
22 | $ flask -A task_app run --debug
23 | ```
24 |
25 | Go to http://localhost:5000/ and use the forms to submit tasks. You can see the polling
26 | requests in the browser dev tools and the Flask logs. You can see the tasks submitting
27 | and completing in the Celery logs.
28 |
--------------------------------------------------------------------------------
/examples/celery/make_celery.py:
--------------------------------------------------------------------------------
1 | from task_app import create_app
2 |
3 | flask_app = create_app()
4 | celery_app = flask_app.extensions["celery"]
5 |
--------------------------------------------------------------------------------
/examples/celery/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "flask-example-celery"
3 | version = "1.0.0"
4 | description = "Example Flask application with Celery background tasks."
5 | readme = "README.md"
6 | classifiers = ["Private :: Do Not Upload"]
7 | dependencies = ["flask", "celery[redis]"]
8 |
9 | [build-system]
10 | requires = ["flit_core<4"]
11 | build-backend = "flit_core.buildapi"
12 |
13 | [tool.flit.module]
14 | name = "task_app"
15 |
16 | [tool.ruff]
17 | src = ["src"]
18 |
--------------------------------------------------------------------------------
/examples/celery/requirements.txt:
--------------------------------------------------------------------------------
1 | #
2 | # This file is autogenerated by pip-compile with Python 3.11
3 | # by the following command:
4 | #
5 | # pip-compile --resolver=backtracking pyproject.toml
6 | #
7 | amqp==5.1.1
8 | # via kombu
9 | async-timeout==4.0.2
10 | # via redis
11 | billiard==3.6.4.0
12 | # via celery
13 | blinker==1.6.2
14 | # via flask
15 | celery[redis]==5.2.7
16 | # via flask-example-celery (pyproject.toml)
17 | click==8.1.3
18 | # via
19 | # celery
20 | # click-didyoumean
21 | # click-plugins
22 | # click-repl
23 | # flask
24 | click-didyoumean==0.3.0
25 | # via celery
26 | click-plugins==1.1.1
27 | # via celery
28 | click-repl==0.2.0
29 | # via celery
30 | flask==2.3.2
31 | # via flask-example-celery (pyproject.toml)
32 | itsdangerous==2.1.2
33 | # via flask
34 | jinja2==3.1.2
35 | # via flask
36 | kombu==5.2.4
37 | # via celery
38 | markupsafe==2.1.2
39 | # via
40 | # jinja2
41 | # werkzeug
42 | prompt-toolkit==3.0.38
43 | # via click-repl
44 | pytz==2023.3
45 | # via celery
46 | redis==4.5.4
47 | # via celery
48 | six==1.16.0
49 | # via click-repl
50 | vine==5.0.0
51 | # via
52 | # amqp
53 | # celery
54 | # kombu
55 | wcwidth==0.2.6
56 | # via prompt-toolkit
57 | werkzeug==2.3.3
58 | # via flask
59 |
--------------------------------------------------------------------------------
/examples/celery/src/task_app/__init__.py:
--------------------------------------------------------------------------------
1 | from celery import Celery
2 | from celery import Task
3 | from flask import Flask
4 | from flask import render_template
5 |
6 |
7 | def create_app() -> Flask:
8 | app = Flask(__name__)
9 | app.config.from_mapping(
10 | CELERY=dict(
11 | broker_url="redis://localhost",
12 | result_backend="redis://localhost",
13 | task_ignore_result=True,
14 | ),
15 | )
16 | app.config.from_prefixed_env()
17 | celery_init_app(app)
18 |
19 | @app.route("/")
20 | def index() -> str:
21 | return render_template("index.html")
22 |
23 | from . import views
24 |
25 | app.register_blueprint(views.bp)
26 | return app
27 |
28 |
29 | def celery_init_app(app: Flask) -> Celery:
30 | class FlaskTask(Task):
31 | def __call__(self, *args: object, **kwargs: object) -> object:
32 | with app.app_context():
33 | return self.run(*args, **kwargs)
34 |
35 | celery_app = Celery(app.name, task_cls=FlaskTask)
36 | celery_app.config_from_object(app.config["CELERY"])
37 | celery_app.set_default()
38 | app.extensions["celery"] = celery_app
39 | return celery_app
40 |
--------------------------------------------------------------------------------
/examples/celery/src/task_app/tasks.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from celery import shared_task
4 | from celery import Task
5 |
6 |
7 | @shared_task(ignore_result=False)
8 | def add(a: int, b: int) -> int:
9 | return a + b
10 |
11 |
12 | @shared_task()
13 | def block() -> None:
14 | time.sleep(5)
15 |
16 |
17 | @shared_task(bind=True, ignore_result=False)
18 | def process(self: Task, total: int) -> object:
19 | for i in range(total):
20 | self.update_state(state="PROGRESS", meta={"current": i + 1, "total": total})
21 | time.sleep(1)
22 |
23 | return {"current": total, "total": total}
24 |
--------------------------------------------------------------------------------
/examples/celery/src/task_app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Celery Example
6 |
7 |
8 |
Celery Example
9 | Execute background tasks with Celery. Submits tasks and shows results using JavaScript.
10 |
11 |
12 |
Add
13 |
Start a task to add two numbers, then poll for the result.
14 |
19 |
Result:
20 |
21 |
22 |
Block
23 |
Start a task that takes 5 seconds. However, the response will return immediately.
24 |
27 |
28 |
29 |
30 |
Process
31 |
Start a task that counts, waiting one second each time, showing progress.
32 |
36 |
37 |
38 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/examples/celery/src/task_app/views.py:
--------------------------------------------------------------------------------
1 | from celery.result import AsyncResult
2 | from flask import Blueprint
3 | from flask import request
4 |
5 | from . import tasks
6 |
7 | bp = Blueprint("tasks", __name__, url_prefix="/tasks")
8 |
9 |
10 | @bp.get("/result/")
11 | def result(id: str) -> dict[str, object]:
12 | result = AsyncResult(id)
13 | ready = result.ready()
14 | return {
15 | "ready": ready,
16 | "successful": result.successful() if ready else None,
17 | "value": result.get() if ready else result.result,
18 | }
19 |
20 |
21 | @bp.post("/add")
22 | def add() -> dict[str, object]:
23 | a = request.form.get("a", type=int)
24 | b = request.form.get("b", type=int)
25 | result = tasks.add.delay(a, b)
26 | return {"result_id": result.id}
27 |
28 |
29 | @bp.post("/block")
30 | def block() -> dict[str, object]:
31 | result = tasks.block.delay()
32 | return {"result_id": result.id}
33 |
34 |
35 | @bp.post("/process")
36 | def process() -> dict[str, object]:
37 | result = tasks.process.delay(total=request.form.get("total", type=int))
38 | return {"result_id": result.id}
39 |
--------------------------------------------------------------------------------
/examples/javascript/.gitignore:
--------------------------------------------------------------------------------
1 | .venv/
2 | *.pyc
3 | __pycache__/
4 | instance/
5 | .cache/
6 | .pytest_cache/
7 | .coverage
8 | htmlcov/
9 | dist/
10 | build/
11 | *.egg-info/
12 | .idea/
13 | *.swp
14 | *~
15 |
--------------------------------------------------------------------------------
/examples/javascript/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2010 Pallets
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/examples/javascript/README.rst:
--------------------------------------------------------------------------------
1 | JavaScript Ajax Example
2 | =======================
3 |
4 | Demonstrates how to post form data and process a JSON response using
5 | JavaScript. This allows making requests without navigating away from the
6 | page. Demonstrates using |fetch|_, |XMLHttpRequest|_, and
7 | |jQuery.ajax|_. See the `Flask docs`_ about JavaScript and Ajax.
8 |
9 | .. |fetch| replace:: ``fetch``
10 | .. _fetch: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
11 |
12 | .. |XMLHttpRequest| replace:: ``XMLHttpRequest``
13 | .. _XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
14 |
15 | .. |jQuery.ajax| replace:: ``jQuery.ajax``
16 | .. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/
17 |
18 | .. _Flask docs: https://flask.palletsprojects.com/patterns/javascript/
19 |
20 |
21 | Install
22 | -------
23 |
24 | .. code-block:: text
25 |
26 | $ python3 -m venv .venv
27 | $ . .venv/bin/activate
28 | $ pip install -e .
29 |
30 |
31 | Run
32 | ---
33 |
34 | .. code-block:: text
35 |
36 | $ flask --app js_example run
37 |
38 | Open http://127.0.0.1:5000 in a browser.
39 |
40 |
41 | Test
42 | ----
43 |
44 | .. code-block:: text
45 |
46 | $ pip install -e '.[test]'
47 | $ coverage run -m pytest
48 | $ coverage report
49 |
--------------------------------------------------------------------------------
/examples/javascript/js_example/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 | from js_example import views # noqa: E402, F401
6 |
--------------------------------------------------------------------------------
/examples/javascript/js_example/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 | JavaScript Example
3 |
4 |
5 |
14 |