Валидация формы с помощью WTForms¶
Когда вам приходится работать с данными формы, отправленными через браузер, код быстро становится трудночитаемым. Существуют библиотеки, призванные облегчить управление этим процессом. Одной из них является WTForms, которую мы рассмотрим здесь. Если вы окажетесь в ситуации, когда у вас много форм, вы, возможно, захотите попробовать ее.
При работе с WTForms вы должны сначала определить свои формы как классы. Для этого я рекомендую разбить приложение на несколько модулей (Большие приложения в виде пакетов) и добавить отдельный модуль для форм.
Получение максимальной отдачи от WTForms с помощью расширения
Расширение Flask-WTF развивает этот шаблон и добавляет несколько небольших помощников, которые делают работу с формами и Flask более увлекательной. Вы можете получить его по адресу PyPI.
Формы¶
Вот пример формы для типичной страницы регистрации:
from wtforms import Form, BooleanField, StringField, PasswordField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
В представлении¶
В функции просмотра использование этой формы выглядит следующим образом:
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
user = User(form.username.data, form.email.data,
form.password.data)
db_session.add(user)
flash('Thanks for registering')
return redirect(url_for('login'))
return render_template('register.html', form=form)
Обратите внимание, что здесь мы подразумеваем, что представление использует SQLAlchemy (SQLAlchemy во Flask), но это, конечно, не обязательное условие. Адаптируйте код по мере необходимости.
О чем следует помнить:
создать форму из значения запроса
form
, если данные отправлены через метод HTTPPOST
иargs
, если данные отправлены какGET
.для проверки данных вызовите метод
validate()
, который вернетTrue
, если данные подтвердятся,False
в противном случае.для доступа к отдельным значениям из формы, обратитесь к form.<NAME>.data.
Формы в шаблонах¶
Теперь перейдем к стороне шаблонов. Когда вы передаете форму в шаблоны, вы можете легко визуализировать их там. Посмотрите на следующий пример шаблона, чтобы увидеть, насколько это просто. WTForms уже делает половину генерации формы за нас. Чтобы сделать это еще приятнее, мы можем написать макрос, который отображает поле с меткой и список ошибок, если таковые имеются.
Вот пример шаблона _formhelpers.html
с таким макросом:
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
Этот макрос принимает несколько аргументов ключевых слов, которые передаются в функцию поля WTForm, которая создает поле для нас. Аргументы ключевых слов будут вставлены как атрибуты HTML. Так, например, вы можете вызвать render_field(form.username, class='username')
, чтобы добавить класс к элементу ввода. Обратите внимание, что WTForms возвращает стандартные строки Python, поэтому мы должны сообщить Jinja2, что эти данные уже преобразованы в HTML с помощью фильтра |safe
.
Вот шаблон register.html
для функции, которую мы использовали выше, использующий преимущества шаблона _formhelpers.html
:
{% from "_formhelpers.html" import render_field %}
<form method=post>
<dl>
{{ render_field(form.username) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm) }}
{{ render_field(form.accept_tos) }}
</dl>
<p><input type=submit value=Register>
</form>
Более подробную информацию о WTForms можно найти на сайте WTForms website.