Flask-WTFを使ってフォームを作成し、バリデーション機能を使用する

Flask-WTFとWTFormsの違いがよくわかっていませんが、今回は、Flask-WTFを使ってフォームを作成します。

Flask-WTFやWTFormsでフォームを作成すると、バリデーション機能が使えて便利なようです。

ちなみに、バリデーションとは、

バリデーションとは、入力されたデータが、あるいはプログラミング言語やマークアップ言語の記述が、規定された文法に即して、または要求された仕様にそって、適切に記述されているかどうかを検証することである。

多くの場合、プログラミング言語においてフォームなどに入力された文字列が入力規則に対して妥当に記述されているかどうかを検証する仕組みを指す。記述が妥当でない場合はエラーとして値を返すように設定される。

出典:IT用語辞典バイナリ

インストール

まずは、Flask-WTFをインストールします。

pip install flask-wtf

wtforms.validatorsのEmail()を使うには、email-validatorが無いとエラーがでたので、email-validatorもインストールします。

pip install email-validator
--- or ---
pip install wtforms[email]

app.py

よく使いそうなフィールドを作成して、テストしていきます。

StringFieldTextAreaField
IntegerFieldBooleanField
EmailFieldSubmitField
PasswordField
from flask import Flask, render_template

from flask_wtf import FlaskForm

from wtforms import (
    StringField,
    IntegerField,
    EmailField,
    PasswordField,
    TextAreaField,
    BooleanField,
    SubmitField
)

from wtforms.validators import (
    DataRequired,
    NumberRange,
    Email,
    EqualTo,
    Length
)

app = Flask(__name__)
app.config['SECRET_KEY'] = 'dev'

class SampleForm(FlaskForm):
    name = StringField('Name:', validators=[DataRequired()])
    age = IntegerField('Age:', validators=[NumberRange(min=20,max=40,message='Out of Range 20-40')])
    email = EmailField('Email:', validators=[DataRequired(),Email('Enter A Valid Email Address')])
    password = PasswordField('Password:', validators=[
        Length(min=1, max=6),
        EqualTo('confirm', message='Passwords must match')
    ])
    confirm = PasswordField('Repeat Password')
    comment = TextAreaField('Comment:')
    accept = BooleanField('I accept',validators=[DataRequired()])
    submit = SubmitField('Submit')

@app.route('/', methods=['GET','POST'])
def index():
    form = SampleForm()
    if form.validate_on_submit():
        return '<h1>Name:{}<br>Age:{}<br>Email:{}<br>Password:{}<br>Comment:{}<br>Accept:{}</h1>'.format(
            form.name.data,
            form.age.data,
            form.email.data,
            form.password.data,
            form.comment.data,
            form.accept.data
        )
    return render_template('sample2.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)

sample.html

htmlファイルのformタグ内に、{{ form.csrf_token }}を記述しないと上手く動作しません。

具体的には、app.pyに記述したform.validate_on_submit()が常にFalseになってしまいます。

とくに、スペルミスには要注意です。私は、上手く動かない原因がスペルミスだと気づくまでに、結構時間を無駄にしました。

<body>
    <form method="post">
        <!-- form.csrf_tokenを記述しないと上手く動作しません -->
        <!-- スペルミスに要注意 -->
        {{ form.csrf_token }}

        <dt>{{ form.name.label }}</dt>
        <dd>{{ form.name }} </dd>
        <dt>{{ form.age.label }}</dt>
        <dd>{{ form.age }}</dd>
        <dt>{{ form.email.label }}</dt>
        <dd>{{ form.email }}</dd>
        <dt>{{ form.password.label }}</dt>
        <dd>{{ form.password }}</dd>
        <dt>{{ form.confirm.label }}</dt>
        <dd>{{ form.confirm }}</dd>
        <dt>{{ form.comment.label }}</dt>
        <dd>{{ form.comment }}</dd>
        <dt>{{ form.accept.label }}</dt>
        <dd>{{ form.accept }}</dd>

        {{ form.submit() }}
    </form>
</body>

こんな感じで書いてもいいのですが、コードがクドい上に、エラー処理を入れるとかなり面倒になるので、マクロを使います。

_formhelpers.html

https://flask.palletsprojects.com/en/1.1.x/patterns/wtforms/

このサイトを参考というか、そのままコピーしてマクロを作成しています。

{% 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 %}

sample2.html

<body>
    {% from "_formhelpers.html" import render_field %}
    <form method="post">
        <!-- form.csrf_tokenを記述しないと上手く動作しません -->
        <!-- スペルミスに要注意 -->
        {{ form.csrf_token }}

        {{ render_field(form.name) }}
        {{ render_field(form.age) }}
        {{ render_field(form.email) }}
        {{ render_field(form.password) }}
        {{ render_field(form.confirm) }}
        {{ render_field(form.comment) }}
        {{ render_field(form.accept) }}
        
        {{ form.submit() }}
    </form>
</body>

かなりスッキリして、コードが見やすくなりました。これならミスも減りそうです。

設置デモ

https://dattesar.com/flask-wtf-demo/

参考:WTForms

Fields

詳しくは、こちら → https://wtforms.readthedocs.io/en/3.0.x/fields/#field-definitions

  • BooleanField
  • DateField
  • DateTimeField
  • DateTimeLocalField
  • DecimalField
  • DecimalRangeField
  • EmailField
  • FileField
  • MultipleFileField
  • FloatField
  • IntegerField
  • IntegerRangeField
  • RadioField
  • SelectField
  • SearchField
  • SelectMultipleField
  • SubmitField
  • StringField
  • TelField
  • TimeField
  • URLField

  • HiddenField
  • PasswordField
  • TextAreaField

Validators

くわしくは、こちら → https://wtforms.readthedocs.io/en/stable/validators/

  • DataRequired
  • Email
  • EqualTo
  • InputRequired
  • IPAddress
  • Length
  • MacAddress
  • NumberRange
  • Optional
  • Regexp
  • URL
  • UUID
  • AnyOf
  • NoneOf