Flask-WTF を使ったフォームの作り方
Flask-WTF の使い方。事前に入力項目を定義すると、自動で HTML の入力欄が生成され、入力値のバリデーションチェックを行ってくれる。さらに CSRF ( Cross-site Request Forgery ) 対策がなされている。 Flask-WTF は、 WTForms の Flask 用ラッパー。つまり WTForms の Flask 版。
特徴
- 入力欄を自動生成
- バリデーション機能
- CSRF 対策
- reCAPTCHA 対応
- ファイルアップロード機能
インストール
$ pip install Flask-WTF
使い方
- form.py で入力欄 (フォーム) の定義
- view.py で 1 で作ったフォーム情報 を template に渡す
- template で入力欄の生成
- view.py でバリデーションチェック
ログイン画面を作ってみる。
1. form.py ファイルを作成し、ここに必要な入力項目を定義していく。
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email
class LoginForm(FlaskForm):
email = StringField('Email address', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
submit = SubmitField('Login')
text
型の入力フォームなら StringField()
、 textarea
型なら TextAreaField()
などを定義する。第一引数はラベル名、第二引数はバリデーションのタイプを指定する。
Field のパラメータの詳細
https://wtforms.readthedocs.io/en/stable/fields/#the-field-base-class
Remember me 機能をつけることもできる。remember = BooleanField('Remember me')
2, 4. view.py で LoginForm
インスタンスを作成し、 GET
リクエストだったら、 render_template()
の第二引数に指定し template に渡す。 POST
リクエストだったら、form.validate_on_submit()
で送られてきた入力値のバリデーションチェックを行う。チェックが通らないと、入力画面にエラーメッセージが表示される。( form.py でエラーメッセージを指定しないとデフォルトのメッセージとなる。)
@auth.route('/login', methods=['GET', 'POST'])
def login():
# LoginForm インスタンスの作成
form = LoginForm()
if request.method == 'POST':
# バリデーション
if form.validate_on_submit():
# ログイン後の処理
return redirect(url_for('main.index'))
return render_template('auth/login.html', form=form)
3. templates/login.html ファイルを作る。{{ form.csrf_token }}
は CSRF 対策のためなので記述しておく。
<form action="{{ url_for('auth.login') }}" method="POST">
{{ form.csrf_token }}
{{ form.email.label }} {{ form.email }}
<div>
{% for error in form.email.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
{{ form.password.label }} {{ form.password }}
<div>
{% for error in form.password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
{{ form.submit }}
</form>
バリデーション
種類
https://wtforms.readthedocs.io/en/stable/validators/
DataRequired()
:必須Email()
:メールアドレスに使える文字のみLength(min, max)
:文字数制限NumberRange(min, max)
:数値制限EqualTo(fieldname)
:2 つのフィールドの入力値が同一か(パスワードと確認用パスワードとか)
password = PasswordField('Password', validators=[DataRequired()])
confirm = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('confirm')])
自分でバリデーションを作ることもできる。
https://wtforms.readthedocs.io/en/stable/validators/#custom-validators
エラーメッセージを変える
DataRequired()
のデフォルトエラーメッセージは、「 This field is required. 」となっている。
エラーメッセージを「 Password is required. 」に変える場合には、
password = PasswordField('Password', validators=[DataRequired(message='Password is required.')])
CSRF 対策
この対策を有効にするには、シークレットキーが必要となるので、 config.py で設定した。
# config.py
WTF_CSRF_ENABLED = True
SECRET_KEY = 'secret key'
# WTF_CSRF_SECRET_KEY= 'wtf secret key'
create_app()
で設定することもできる。
app.config['SECRET_KEY'] = 'secret key'
app.config['WTF_CSRF_ENABLED'] = True
デフォルトでは、Flask アプリケーション自体のシークレットキーが使用される。 Flask-WTF ( CSRF ) 用と分けたい場合には、 WTF_CSRF_SECRET_KEY
で設定する。
pytest する際は WTF_CSRF_ENABLED = False
とする。
POST 送信時にデータに csrf_token=g.csrf_token
のようにしてトークンを template に送ってもテスト可能なよう。
https://blog.ikappio.com/handling-csrf-tokens-in-flask-wtf-tests/
template に書いた {{ form.csrf_token }}
は hidden
として出力される。