Основы Flask для начинающих: первое веб-приложение
Основы Flask укладываются в несколько понятий: приложение, маршрут, функция-представление, объект запроса и шаблон. В статье по шагам собрано небольшое приложение: установка, обработка адресов с параметрами, чтение данных из GET и POST, ответ в HTML и JSON. В конце показана структура проекта и расширения, которые понадобятся дальше.

Содержание статьи
Что такое Flask и когда его выбирать
Flask - микрофреймворк для веб-приложений на Python. Приставка "микро" означает, что в ядре есть только самое нужное: маршрутизация и работа с HTTP на базе библиотеки Werkzeug, шаблонизатор Jinja2 и отладочный сервер. Базы данных, формы, авторизацию и админку подключают отдельными расширениями, поэтому проект содержит только то, что ему действительно нужно.
| Критерий | Flask | Django |
|---|---|---|
| Минимальное приложение | Один файл, 5-7 строк | Проект из нескольких файлов, создается командой |
| ORM и админка | Подключаются расширениями | Встроены |
| Структура проекта | Свободная | Задана фреймворком |
| Где удобен | API, небольшие сайты, прототипы, сервисы | Крупные сайты с типовым набором функций |
Для старта нужно знать основы Python: функции, словари, декораторы на уровне "что это такое", а также базовый HTML и устройство HTTP-запроса.
Установка и минимальное приложение
Создайте папку проекта, виртуальное окружение и поставьте пакет:
python -m venv .venv
# Windows: .venv\Scripts\activate Linux и macOS: source .venv/bin/activate
pip install flaskМинимальное приложение помещается в файл app.py:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "<h1>Привет, Flask!</h1>"
if __name__ == "__main__":
app.run(debug=True)Запустите его командой python app.py или flask --app app run --debug и откройте в браузере http://127.0.0.1:5000/. Режим отладки перезапускает сервер при изменении кода и показывает трассировку ошибок прямо на странице. Включать его на рабочем сервере нельзя: отладчик позволяет выполнять произвольный код.
Аргумент __name__ подсказывает Flask, где лежит модуль приложения, чтобы найти рядом папки templates и static. Подробный разбор первого запуска с типичными ошибками есть в статье первое приложение на Flask.
Маршруты и переменные в URL
Декоратор @app.route() связывает адрес с функцией-представлением. Часть адреса можно сделать переменной: она передается в функцию аргументом. Конвертер перед именем задает тип и заодно проверяет значение.
@app.route("/user/<name>")
def profile(name):
return f"Профиль {name}"
@app.route("/post/<int:post_id>")
def post(post_id):
return f"Статья {post_id}, следующая {post_id + 1}" # post_id уже int
@app.route("/files/<path:subpath>")
def files(subpath):
return f"Файл {subpath}" # путь со слешамиАдрес /post/abc не подойдет под конвертер int, и Flask сам вернет ошибку 404. Кроме int есть string (по умолчанию, без слешей), float, path и uuid.
Построение ссылок через url_for
Функция url_for("post", post_id=5) строит адрес по имени функции-представления и вернет /post/5. Если позже поменять шаблон адреса в декораторе, ссылки в шаблонах и редиректах обновятся автоматически, поэтому адреса в коде вручную не пишут.
Запрос и ответ
По умолчанию маршрут принимает только GET. Чтобы обработать отправку формы, перечислите методы в параметре methods. Данные запроса доступны через объект request: request.args содержит параметры строки адреса, request.form поля формы, request.get_json() тело запроса в формате JSON.
from flask import Flask, request, redirect, url_for, abort
app = Flask(__name__)
NOTES = {1: "Купить хлеб"}
@app.route("/notes", methods=["GET", "POST"])
def notes():
if request.method == "POST":
text = request.form.get("text", "").strip()
if not text:
abort(400)
NOTES[max(NOTES) + 1] = text
return redirect(url_for("notes"))
limit = request.args.get("limit", default=10, type=int)
return {"notes": list(NOTES.values())[:limit]}Функция может вернуть строку (будет HTML), словарь или список (Flask превратит их в JSON с правильным заголовком), а также кортеж вида (тело, код_ответа), например return "Создано", 201. Функция abort(404) прерывает обработку и отдает страницу ошибки, redirect() перенаправляет браузер на другой адрес.
После успешного POST принято делать редирект на GET-страницу. Тогда обновление страницы в браузере не отправит форму повторно.
Шаблоны Jinja2
Собирать HTML строками неудобно и опасно, для этого есть шаблоны. Файлы шаблонов кладут в папку templates рядом с приложением и вызывают через render_template(), передавая переменные именованными аргументами.
from flask import render_template
@app.route("/list")
def note_list():
return render_template("notes.html", title="Заметки", notes=NOTES)<!-- templates/notes.html -->
{% extends "base.html" %}
{% block content %}
<h1>{{ title }}</h1>
<ul>
{% for id, text in notes.items() %}
<li><a href="{{ url_for('post', post_id=id) }}">{{ text }}</a></li>
{% else %}
<li>Заметок нет</li>
{% endfor %}
</ul>
{% endblock %}Двойные фигурные скобки выводят значение, конструкции {% %} задают логику: циклы, условия, наследование. Jinja2 экранирует HTML в выводимых переменных, поэтому текст от пользователя с тегом <script> отобразится как текст, а не выполнится. Наследование через extends и block позволяет держать шапку и подвал в одном базовом файле, подробнее об этом в статье про создание шаблона Flask.
Структура проекта и следующие шаги
Когда приложение вырастает из одного файла, его раскладывают по папкам. Типичная структура небольшого проекта:
project/
app.py # создание приложения и маршруты
config.py # настройки, SECRET_KEY
templates/ # HTML-шаблоны Jinja2
static/ # CSS, JavaScript, картинки
instance/ # локальная база и секреты, не в gitФайлы из static подключаются в шаблоне через url_for('static', filename='style.css'). Для сессий, flash-сообщений и защиты форм приложению нужен SECRET_KEY: длинная случайная строка, которую хранят вне репозитория. В крупных проектах маршруты делят на модули с помощью Blueprint.
Дальше обычно подключают расширения:
- Flask-WTF для форм с проверкой полей и защитой от CSRF, пример в статье про формы Flask;
- Flask-SQLAlchemy или модуль sqlite3 для хранения данных, см. базу данных во Flask;
- Flask-Login для входа пользователей и разграничения доступа.
Для рабочего сервера встроенный сервер разработки не подходит: приложение запускают через WSGI-сервер, например gunicorn или waitress, за веб-сервером nginx. Подробности есть в официальной документации Flask.
Частые вопросы
Ответы на вопросы, которые чаще всего возникают при первом знакомстве с Flask.
Почему изменения в коде не видны в браузере?
Сервер запущен без режима отладки и не перезагружается сам. Запустите его с --debug или app.run(debug=True). Если не обновляются CSS-файлы, дело в кеше браузера: обновите страницу с очисткой кеша.
Как сменить порт и открыть сайт с другого устройства?
Передайте параметры: app.run(host="0.0.0.0", port=8000) или flask --app app run --host 0.0.0.0 --port 8000. Сервер станет доступен по IP-адресу компьютера в локальной сети.
Подходит ли Flask для API?
Да, представление может просто возвращать словарь, и Flask отдаст JSON. Для больших API добавляют проверку входных данных, например через Pydantic или marshmallow.
Где хранить данные между запросами?
Глобальные переменные вроде NOTES из примеров подходят только для учебы: они пропадут при перезапуске и не работают при нескольких процессах сервера. Для данных нужна база, а для данных конкретного пользователя объект session.