Собираем приложение: блог от и до
Пора соединить всё изученное в одно приложение — блог с авторами, постами, формами и шаблонами. Цель — увидеть, как кирпичики складываются в систему.
Отдельные темы — это детали. Сила в их связке: фабрика собирает приложение, блюпринт группирует маршруты, модели хранят данные, формы валидируют ввод, шаблоны рисуют страницы. Разберём поток данных через все слои на примере «создать пост».
Спроектируем блог. Структура — по канонам из раздела про фабрику:
blog/ ├── blog/ │ ├── __init__.py # create_app() │ ├── extensions.py # db = SQLAlchemy() │ ├── models.py # User, Post │ ├── forms.py # PostForm (Flask-WTF) │ ├── views.py # блюпринт posts │ └── templates/ # base.html, list.html, form.html ├── config.py └── requirements.txt
Поток «создать пост» проходит через все слои, которые мы изучили:
GET /posts/new
│ view создаёт PostForm, render_template(form)
▼ пользователь заполняет, сабмит
POST /posts/new
│ form.validate_on_submit() (валидация + CSRF)
├─ невалидно → показать форму с ошибками
└─ валидно:
Post(title=form.title.data, author=current)
db.session.add(post); commit()
flash("Пост создан")
redirect(url_for("posts.list")) ← PRG
Блюпринт группирует связанные маршруты и регистрируется в фабрике:
# views.py
from flask import Blueprint, render_template, redirect, url_for, flash
posts = Blueprint("posts", __name__, url_prefix="/posts")
@posts.route("/")
def list():
items = db.session.execute(select(Post)).scalars().all()
return render_template("list.html", posts=items)
@posts.route("/new", methods=["GET", "POST"])
def new():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data, body=form.body.data)
db.session.add(post)
db.session.commit()
flash("Пост создан", "success")
return redirect(url_for("posts.list"))
return render_template("form.html", form=form)
Главный навык этого урока — мыслить приложение как конвейер слоёв с чётким разделением ответственности. Запрос входит сверху и идёт вниз: маршрутизация выбирает view, форма валидирует и отбивает CSRF, модель пишет в базу через сессию, шаблон рендерит безопасный HTML, ответ уходит наружу. Каждый слой знает только своё дело, и это делает код тестируемым и изменяемым: можно поменять вёрстку, не трогая модель, или базу, не трогая шаблоны. View в этой схеме — тонкий дирижёр: он оркеструет слои, но не содержит тяжёлой логики, которую выносят в сервисы. Поток «создать сущность» — валидация, запись, flash, PRG-редирект — ты будешь воспроизводить почти в каждом действии, меняющем данные.
Как работает под капотом
Запрос проходит конвейер слоёв сверху вниз и собирает ответ. Каждый слой отвечает за своё: маршрутизация выбирает view, форма валидирует, модель пишет в базу, шаблон рисует.
HTTP-запрос
▼ маршрутизация (блюпринт + route)
view-функция
▼ форма (валидация + CSRF)
модель (db.session → база)
▼ данные
шаблон Jinja (наследование, автоэкранирование)
▼
HTTP-ответ
Смоделируем этот конвейер обработки запроса обычным Python — увидишь, как слои передают данные дальше.
db_posts = []
def validate_form(form): # слой формы
errors = {}
if not form.get("title", "").strip():
errors["title"] = "Заголовок обязателен"
return errors
def save_post(form): # слой модели
post = {"id": len(db_posts) + 1, "title": form["title"]}
db_posts.append(post)
return post
def handle(method, form): # view-функция
if method == "POST":
errors = validate_form(form)
if errors:
return ("200", "форма с ошибками", errors)
save_post(form)
return ("302", "/posts", None) # PRG
return ("200", "пустая форма", {})
print(handle("POST", {"title": "Привет, Flask"}))
print(handle("POST", {"title": ""}))
print("в базе постов:", len(db_posts))
Запусти: валидный POST сохраняет пост и отдаёт редирект, пустой возвращает ошибки. Это скелет реального view блога — только вместо словарей реальные форма, модель и шаблон.
Частые ошибки
- Толстые view. Бизнес-логику выноси в сервисы/модели; view — только оркестрация.
- Забыть url_prefix или имя блюпринта в url_for. Ссылка — "posts.list", а не "list".
- Логика в шаблонах. Готовь данные во view, шаблон только отображает.
Best practices
- Группируй маршруты по блюпринтам (posts, auth, admin).
- Один поток на действие: валидация → запись → flash → PRG-редирект.
- Держи слои разделёнными: маршрут, форма, модель, шаблон — каждый о своём.
Что запомнить
- Приложение — конвейер слоёв, собранный фабрикой.
- Запрос идёт: маршрут → форма → модель → шаблон → ответ.
- View — тонкий дирижёр; тяжёлую логику выносят в сервисы.
- Типовое действие: валидация → запись → flash → PRG-редирект.
Итог: приложение — это конвейер слоёв, собранный фабрикой. Запрос идёт маршрут → форма → модель → шаблон → ответ. Дальше — блюпринты подробнее как способ масштабировать структуру.