0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python】Flask + WTFormsでバリデーション付きの入力フォームを作成する

Posted at

※この記事は、私が運営している技術ブログ(hirahira.blog)で公開していた内容を移植・加筆したものです。

FlaskとWTFormsを使ってシンプルなフォーム画面を作成する方法を解説します。

WTFormsとはFlaskでフォームを作成する際に使用されるライブラリです。

WTFormsを使うことにより、バリデーションやセキュリティ対策を簡単に行うことができます。

環境

  • Windows 11
  • Python 3.13.2
  • Flask 3.1.0
  • WTForms 3.2.1

準備

以下の2コマンドを実行して、FlaskとWTFormsをインストールしてください。

  • pip install flask
  • pip install wtforms

構成

以下の構成でフォルダとファイルを作成します。

├ app.py
└ templates/
 ├ register.html
 ├ registered.html
 └ formhelpers.html

コード内容の解説

app.py

メインとなる処理を記述しています。

Registrationクラスで、各入力項目に対するバリデーション内容の定義を行っています。

app.py
from flask import Flask, redirect, render_template, request, session, url_for

# Formクラス及び使用するフィールドをインポート
from wtforms import (
   Form, BooleanField, IntegerField, PasswordField, StringField,
   SubmitField, TextAreaField)

# 使用するvalidatorをインポート
from wtforms.validators import DataRequired, EqualTo, Length, NumberRange

app = Flask(__name__)

# セッションで使用するシークレットキーを設定。本来はランダムな文字列が望ましい
app.config['SECRET_KEY'] = 'secret_key'

# wtformsのFormクラスを継承。それぞれの入力項目に対するバリデーションを設定
class Registration(Form):
   name = StringField('名前:', validators=[DataRequired()])
   age = IntegerField('年齢:', validators=[NumberRange(0, 100, '年齢は0から100の間で入力してください')])
   password = PasswordField('パスワード:', validators=[
       Length(1, 10, 'パスワードは1文字以上10文字以内で入力してください'),
       EqualTo('re_password', 'パスワードが一致しません')
   ])
   re_password = PasswordField('パスワード再入力:')
   comment = TextAreaField('コメント:')
   accept = BooleanField('内容確認:', validators=[DataRequired(message='内容確認にチェックを入れてください')])
   submit = SubmitField('送信')

# POSTかつバリデーションエラーがない場合は、セッションに入力内容を格納してregistered.htmlを表示
@app.route('/', methods=['GET', 'POST'])
def index():
   form = Registration(request.form) 
   if request.method == 'POST' and form.validate():
       # 入力内容をセッションに保存
       session['name'] = form.name.data
       session['age'] = form.age.data
       session['comment'] = form.comment.data
       return redirect(url_for('registered'))
   return render_template('register.html', form=form)

@app.route('/registered')
def registered():
   return render_template('registered.html')

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

register.html

入力フォーム画面です。

下で紹介するrender_fieldマクロをインポートして使っています。

{{ form.csrf_token }}は、CSRF(クロスサイトリクエストフォージェリ)対策用のトークンを生成するための記述です。

register.html
<html lang="ja">
 <head>
   <meta charset="UTF-8" />
   <title>Form</title>
 </head>
 <body>
   <!-- formhelpers.htmlで定義したrender_fieldマクロをインポート -->
   {% from "formhelpers.html" import render_field %}
   <form method="POST">
     {{ form.csrf_token }}
     {{ render_field(form.name) }}
     {{ render_field(form.age) }}
     {{ render_field(form.password) }}
     {{ render_field(form.re_password) }}
     {{ render_field(form.accept) }}
     {{ render_field(form.comment) }}
     {{ form.submit() }}
   </form>
 </body>
</html>

formhelpers.html

フォーム画面を整形し、エラー内容を表示する処理を、jinja2のマクロ機能を使って定義しています。

{{ field(**kwargs)|safe }}のようにsafeを付けるとHTMLをエスケープせずに表示することができます。(WTForms側でエスケープしてくれる)

formhelpers.html
<!-- よく使用する処理をマクロ(関数)として定義 -->
{% macro render_field(field) %}
<dt>{{ field.label }}</dt>
<dd>{{ field(**kwargs)|safe }}</dd>
{% if field.errors %}
<ul class="error">
 {% for error in field.errors %}
   <li>{{ error }}</li>
 {% endfor %}
</ul>
{% endif %}
{% endmacro %}

registered.html

登録内容を表示する画面です。

registered.html
<html lang="ja">
 <head>
   <meta charset="UTF-8" />
   <title>registerd</title>
 </head>
 <body>
   <h1>登録内容</h1>
   <ul>
     <li>名前:{{ session['name'] }}</li>
     <li>年齢:{{ session['age'] }}</li>
     <li>コメント:{{ session['comment'] }}</li>
   </ul>
 </body>
</html>

動作確認

python app.py を実行し、http://127.0.0.1:5000 にアクセスするとフォーム画面が表示されます。
image.png

不正な値を入力後に送信ボタンをクリックすると、エラーメッセージが表示されます。
image.png

正しい情報を入力して送信ボタンを押すとregisterd.htmlに遷移し、入力した内容が表示されます。
image.png

参考記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?