Обработка форм вручную и валидация
Форма — это диалог: пользователь шлёт данные, сервер их проверяет и либо принимает, либо возвращает с ошибками. Валидация на сервере обязательна всегда.
Никогда не доверяй вводу пользователя. Проверки в браузере (required, pattern) — лишь удобство; их легко обойти. Настоящая защита — серверная валидация: проверь каждое поле, собери ошибки, при провале покажи форму снова с подсказками.
Обработка формы — это цикл: показать (GET) → принять (POST) → проверить → сохранить или вернуть с ошибками. Сначала разберём ручной способ — он показывает механику, которую потом автоматизирует Flask-WTF.
@app.route("/register", methods=["GET", "POST"])
def register():
errors = {}
if request.method == "POST":
name = request.form.get("name", "").strip()
email = request.form.get("email", "").strip()
if not name:
errors["name"] = "Имя обязательно"
if "@" not in email:
errors["email"] = "Некорректный email"
if not errors:
# сохранить ...
return redirect(url_for("success"))
return render_template("register.html", errors=errors)
Логика: накапливаем ошибки в словарь, по каждому полю своя проверка. Если словарь пуст — данные валидны, сохраняем и редиректим (PRG). Иначе — рендерим форму снова, передав ошибки, чтобы шаблон показал подсказки рядом с полями.
Главная аксиома работы с формами: вход пользователя враждебен по умолчанию. Любые проверки на стороне браузера — required, maxlength, pattern — это лишь удобство интерфейса; их обходят за секунду через curl, Postman или вкладку DevTools. Единственная настоящая граница доверия — сервер, и валидацию там делают всегда, для каждого поля. Хорошая обработка формы накапливает сразу все ошибки (а не падает на первой) и при провале возвращает форму вместе с введёнными значениями, чтобы пользователь не заполнял всё заново. Эту ручную механику важно понять до Flask-WTF, потому что расширение автоматизирует ровно её: те же правила, тот же цикл «проверить — принять или вернуть».
Как работает под капотом
Валидация — это набор правил, прогоняемых по полям. Каждое правило либо проходит, либо добавляет ошибку. Решение «принять или вернуть» зависит от того, пуст ли список ошибок.
POST с данными формы
│
▼
┌──────────────────────────┐
│ для каждого поля: │
│ применить правила │
│ ошибка? → errors[поле] │
└──────────────────────────┘
│
errors пуст? ──да──▶ сохранить → redirect (PRG)
│
нет
▼
показать форму снова + ошибки + введённые данные
Смоделируем валидатор обычным Python — это ровно та логика, что внутри ручной обработки и Flask-WTF.
def validate(form):
errors = {}
name = form.get("name", "").strip()
email = form.get("email", "").strip()
age = form.get("age", "").strip()
if not name:
errors["name"] = "Имя обязательно"
if "@" not in email or "." not in email:
errors["email"] = "Некорректный email"
if not age.isdigit() or int(age) < 0:
errors["age"] = "Возраст должен быть числом"
return errors
print(validate({"name": "Анна", "email": "[email protected]", "age": "20"})) # {}
print(validate({"name": "", "email": "bad", "age": "x"}))
Запусти: валидные данные дают пустой словарь (всё ок), кривые — словарь ошибок по полям. Пустой словарь = зелёный свет на сохранение. Это сердце любой обработки формы.
Частые ошибки
- Полагаться только на проверки браузера. Их обходят за секунду через curl или DevTools. Серверная валидация обязательна.
- Терять введённые данные при ошибке. Верни значения обратно в шаблон, иначе пользователь заполняет всё заново.
- Не делать strip(). Пробелы по краям ломают проверки «непустое поле».
Best practices
- Валидируй на сервере всегда, даже если есть проверки в HTML.
- Накапливай все ошибки сразу, а не показывай по одной.
- При провале возвращай и ошибки, и ранее введённые значения.
Что запомнить
- Серверная валидация обязательна: вход пользователя нельзя считать безопасным.
- Ошибки накапливают по полям; пустой список ошибок = можно сохранять.
- При провале форму показывают снова с ошибками и введёнными данными.
- После успешного сохранения — редирект (PRG).
Итог: обработка формы — это валидация на сервере с накоплением ошибок и повторным показом при провале. Ручной способ раскрывает механику; дальше Flask-WTF автоматизирует её и добавит защиту от CSRF.