• en
  • Language: ru
  • Documentation version: 1.1.x

Валидация формы с помощью 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), но это, конечно, не обязательное условие. Адаптируйте код по мере необходимости.

О чем следует помнить:

  1. создать форму из значения запроса form, если данные отправлены через метод HTTP POST и args, если данные отправлены как GET.

  2. для проверки данных вызовите метод validate(), который вернет True, если данные подтвердятся, False в противном случае.

  3. для доступа к отдельным значениям из формы, обратитесь к 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 unicode, поэтому мы должны сообщить 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.