Flask入門|Flask-WTFの使い方とメリットを学ぶ【チャプター4-07】

一つ前のページではテンプレートマクロについて学習しました。
今回は Flask-WTF について見ていきましょう。
Chapter1:Flask入門編
Chapter2:Jinja2入門編
Chapter3:フィルター編
Chapter4:フォーム編
・Chapter4-1:HTTPとは何か
・Chapter4-2:フォームの基本を理解しよう
・Chapter4-3:WTFormsを理解しよう
・Chapter4-4:フォームのバリデーションを理解しよう
・Chapter4-5:カスタムバリデータを理解しよう
・Chapter4-6:テンプレートマクロを理解しよう
・Chapter4-7:Flask-WTFを理解しよう ◁今回はここ
Chapter5:データベース編
Chapter6:Flaskの便利機能編
Chapter7:アプリ開発編
Chapter4では、HTTPやフォーム、バリデーションの基礎を学びながら、Flaskでフォーム入力を処理する方法を段階的に習得してきました。
ここまでの知識を組み合わせれば、ある程度複雑なフォームの処理も可能になりますが、実際のWebアプリ開発では「安全性」や「記述の簡潔さ」も重要です。
そこで登場するのが「Flask-WTF」という拡張ライブラリです。
これを使うことで、ここまでに学んだ処理が ぐっと整理され、効率的かつ安全に なります。
本記事は 有料記事(100円)ですが、現在は期間限定で無料公開中です。
Flask-WTFとは?基本機能と導入メリットを解説
Flask-WTFの仕組みと活用ポイント
Flask-WTF とは、Flaskでフォームを扱う際に便利なライブラリ「WTForms」を、Flaskにスムーズに統合するための 拡張機能 です。
- Flask + WTForms = Flask-WTF
- 正式には
flask_wtf
モジュールと呼ばれる - WTForms自体はFlask限定のものではない
これを使うことで、次のような利点があります:
- フォーム用テンプレートが簡潔になる
request.form.get()
を自分で書かなくてよい- バリデーションの自動呼び出し
- HTMLフォームに必要な CSRFトークン の自動挿入
コード簡略化とCSRF対策を自動化する利点
Chapter4-1~4-6までは、フォームの処理において以下のような手順が必要でした:
request.method
でGETとPOSTを分岐request.form.get("フィールド名")
で値を取得- 各値に対してバリデーションを手動で実装
- テンプレート内でフィールドのラベルや入力タグを手書き
- セキュリティのためのCSRF対策を自分で考える必要がある
Flask-WTFを使えば、これらが一気に簡単になります。
従来のやり方(手動) | Flask-WTFを使ったやり方 |
---|---|
フィールドの取得・バリデーションを手動 | form.validate_on_submit() で一括処理 |
CSRFトークンを自前で挿入 | 自動で含まれる |
HTMLフォームを自分で記述 | {{ form.フィールド名() }} で簡単表示 |
Flask-WTFの導入手順と構文の基本
Flask-WTFをインストールしよう
まずは Flask-WTF ライブラリをインストールします。
pip install flask-wtf
Flask-WTF は、WTForms に加えて Flask との連携機能を提供してくれるライブラリです。
CSRFトークンの自動生成や、テンプレートでのフィールドレンダリングなど、初心者がつまづきやすいポイントを補ってくれます。
secret_keyの役割と設定方法
Flask-WTFを使うには、Flaskのアプリケーションに「秘密鍵(secret_key)」を設定する必要があります。
from flask import Flask app = Flask(__name__) app.secret_key = "これはCSRFトークンのために必要な秘密鍵"
フォームの中に「CSRFトークン(不正アクセス防止用の特殊な文字列)」が自動的に埋め込まれます。
このトークンの生成に「secret_key」が使われるため、Flask-WTFを使うときは必ず設定しましょう。
FlaskFormを使ったフォーム定義の例
次に、実際に使うフォームのクラスを作成します。
from flask_wtf import FlaskForm # Flask_wtfモジュールのFlaskFormクラスをインポート from wtforms import StringField, SubmitField from wtforms.validators import DataRequired # FlaskFormを継承したNameFormクラスを定義 ⇒ Flaskアプリで使用可能に class NameForm(FlaskForm): name = StringField("名前", validators=[DataRequired()]) submit = SubmitField("送信") # 送信ボタンを定義(ラベルは「送信」)
FlaskForm
はすべてのフォームクラスの基底クラスです。StringField("名前")
は、テキスト入力欄の部品で、「名前」というラベルが付きます。SubmitField("送信")
は送信ボタンです。DataRequired()
は「この欄は必須です」というバリデーション(入力チェック)を担当します。
これで フォームの定義(形・バリデーション) が完了 です。
次はこれを使って、Webアプリとしてどう動かすのかを見ていきましょう。
Flask-WTF導入前後のコード比較で理解を深めよう
手動処理でフォームを実装する方法
from flask import Flask, request, render_template app = Flask(__name__) @app.route("/hello", methods=["GET", "POST"]) def hello(): name = "" if request.method == "POST": name = request.form.get("name") # フォームから送られてきた値を取り出す return render_template("hello.html", name=name)
<form method="POST"> <input type="text" name="name"> <!-- 入力欄 --> <input type="submit" value="送信"> <!-- ボタン --> </form> {% if name %} <p>こんにちは、{{ name }}さん!</p> {% endif %}
- 値の取得やチェックを毎回自分で書かないといけない
- バリデーション(未入力など)も自分で作る必要がある
- セキュリティ(CSRF対策)も入っていない
Flask-WTFでフォームを簡単かつ安全に処理
from flask import Flask, render_template from flask_wtf import FlaskForm # Flask_wtfモジュールのFlaskFormクラスをインポート from wtforms import StringField, SubmitField from wtforms.validators import DataRequired app = Flask(__name__) app.secret_key = "secret" # CSRF保護のために必須 class NameForm(FlaskForm): # FlaskFormを継承したNameFormクラスを定義 ⇒ Flaskアプリで使用可能に name = StringField("名前", validators=[DataRequired()]) submit = SubmitField("送信") # 送信ボタンを定義(ラベルは「送信」) @app.route("/hello", methods=["GET", "POST"]) def hello(): form = NameForm() name = "" if form.validate_on_submit(): # POSTかつバリデーション成功時 name = form.name.data # 入力された値を取得 return render_template("hello.html", form=form, name=name)
<form method="POST"> {{ form.csrf_token }} <!-- CSRFトークンが自動で出力される --> {{ form.name.label }} <!-- 「名前」というラベル --> {{ form.name() }} <!-- 入力欄(自動で name="name" になる) --> {{ form.submit() }} <!-- 送信ボタン --> </form> {% if name %} <p>こんにちは、{{ name }}さん!</p> {% endif %}
改善点 | 解説 |
---|---|
form.validate_on_submit() | 「POSTかつバリデーション成功時」の判定を1行で書ける |
form.name.data | 入力された値が自動で格納される |
form.name() | HTMLの入力タグが自動生成される(name属性なども含む) |
form.csrf_token | セキュリティ対策(CSRF)が自動挿入される |
form.submit() | HTMLの送信ボタンも自動で表示される |
- フォーム定義もHTMLの表示も部品化されてスッキリ
- セキュリティも安心
- エラー処理や再表示にも強い
まとめ|Flask-WTFでフォーム開発をシンプル&安全に
Flask-WTFは、これまで学んできたフォーム処理・バリデーション・CSRF対策をすべてまとめて支援してくれる、非常に強力なツールです。
書くコードが減るだけでなく、セキュリティも高まり、保守性の高いアプリが作れるようになります。
「フォームの扱いが大変そう…」と感じていた人も、Flask-WTFを使えばスッキリ書けて、理解しやすくなるはずです。
練習問題:Flask-WTFでCSRF付きのフォームを作ってみよう
Flask-WTFを使うことで、Flask上でフォームを簡単かつ安全に扱うことができます。
この問題では、好きなフルーツの名前をユーザーに入力してもらい、それを画面上に表示するWebアプリを作成してください。
フォームにはバリデーション(未入力エラー)をつけ、送信後は「〇〇は美味しそうですね!」という日本語のメッセージを表示するようにします。
テンプレートファイル(HTML)は↓↓のコードを使用し、アプリファイル(Python)を作成してください。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>フルーツフォーム</title> </head> <body> <h1>好きなフルーツを教えてください</h1> <!-- フォーム開始。POSTメソッドで送信 --> <form method="POST"> {{ form.csrf_token }} <!-- CSRF対策トークン(Flask-WTFが自動で挿入) --> <p> {{ form.fruit_name.label }}<br> <!-- ラベル表示 --> {{ form.fruit_name(size=30) }} <!-- 入力フィールドのHTML表示 --> </p> <p> {{ form.submit() }} <!-- 送信ボタンのHTML出力 --> </p> </form> <!-- 結果があれば表示 --> {% if result %} <p><strong>{{ result }}</strong></p> {% endif %} </body> </html>
この問題の要件
以下の要件に従ってコードを完成させてください。
以下の条件をすべて満たすPythonファイル(app.py
)を作成してください。
- Flask-WTFのフォームクラスを
FruitForm
という名前で作成すること。 - フォームには以下の2つの項目を含めること:
fruit_name
:入力必須のテキスト入力欄submit
:送信ボタン
- CSRFトークン保護を設定すること。
- フォームの送信が成功した場合、入力されたフルーツ名に対して「〇〇は美味しそうですね!」というメッセージを作成し、テンプレートへ渡すこと。
form.validate_on_submit()
を使ってバリデーションとPOST送信チェックを行うこと。
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
- ヒント:コードの構成を見る
-
正解のコードは上から順に以下のような構成となっています。
1:必要なライブラリをすべてインポート
→ Flask本体のほか、Flask-WTFとWTForms関連の部品も読み込みます。2:Flaskアプリの本体を作成し、CSRF対策のための「secret_key」を設定
→ フォームを安全に使うために必要な準備です。3:「FruitForm」という名前のフォームクラスを定義
→ この中で、テキスト入力欄(フルーツ名)と送信ボタンを定義します。
→ 入力は必須にしたいため、バリデーションの指定も行います。4:「/fruit」というURLにアクセスしたときにフォームを表示する関数を定義
→ この関数では、フォームのオブジェクトを作り、テンプレートに渡す準備をします。5:フォームが送信されたかどうか、そして入力内容が正しいかをチェック
→ 条件を満たす場合は、入力されたフルーツ名を取り出し、表示用のメッセージを作ります。6:フォームオブジェクトとメッセージをテンプレートに渡して表示
→ 表示のためにrender_template()
を使い、テンプレートファイル(fruit.html)に情報を渡します。7:このPythonファイルが直接実行されたときだけアプリが起動するように設定
→ アプリのエントリーポイント(if name == “main”:)を忘れずに書きましょう。
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
正解コード
例えば、以下のようなプログラムが考えられます。
- 正解コード
-
from flask import Flask, render_template from flask_wtf import FlaskForm # Flask-WTFの基本クラス from wtforms import StringField, SubmitField # 入力欄とボタン from wtforms.validators import DataRequired # 入力必須のバリデータ app = Flask(__name__) app.secret_key = "これはCSRF対策のために必要な秘密鍵です" # フォームクラスの定義 class FruitForm(FlaskForm): # フルーツ名を入力する欄。空欄禁止(DataRequired)バリデーション付き fruit_name = StringField("好きなフルーツの名前", validators=[DataRequired()]) # 送信ボタン submit = SubmitField("送信する") # フォームを表示・処理するルート @app.route("/fruit", methods=["GET", "POST"]) def fruit(): form = FruitForm() result = None # フォームが送信され、バリデーションが成功したときの処理 if form.validate_on_submit(): # 入力されたフルーツ名を取り出す fruit_name = form.fruit_name.data # 結果メッセージを作成 result = f"{fruit_name}は美味しそうですね!" # フォームと結果メッセージをテンプレートに渡す return render_template("fruit.html", form=form, result=result) # このファイルが直接実行されたときだけアプリを起動 if __name__ == "__main__": app.run(debug=True)
正解コードの詳細解説
正解コードをブロックごとに分割して解説します。
- 正解コードの詳細解説
-
必要なライブラリのインポート
from flask import Flask, render_template from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired
ここでは、Flaskアプリを作成するために必要なライブラリを読み込んでいます。
DataRequired
:入力必須(空欄禁止)のバリデーションルール。Flask
:Webアプリ本体を作るためのクラス。render_template
:テンプレート(HTML)を表示するための関数。FlaskForm
:Flask-WTFでフォームを使うときに必要な基本クラス。StringField
:テキスト入力用のフォーム部品。SubmitField
:送信ボタンの部品。
Flaskアプリ本体の作成とセキュリティ設定
app = Flask(__name__) app.secret_key = "これはCSRF対策のために必要な秘密鍵です"
app = Flask(__name__)
:Flaskアプリケーションの本体を作り、変数app
に保存。secret_key
:CSRF対策に必要な暗号鍵。これがあることで不正な送信を防ぐことができる。
フォームのクラスを作成
class FruitForm(FlaskForm): fruit_name = StringField("好きなフルーツの名前", validators=[DataRequired()]) submit = SubmitField("送信する")
Flask-WTFで使うフォームを定義しています。
submit
:送信ボタン。ラベルは「送信する」。FruitForm
:フォームの名前(自由に決められるがわかりやすく)。fruit_name
:ユーザーが入力する「好きなフルーツ名」の欄。ラベルは「好きなフルーツの名前」。validators=[DataRequired()]
:入力を必須にする設定。未入力のまま送信しようとするとエラーになる。
ルーティングとフォーム処理
@app.route("/fruit", methods=["GET", "POST"]) def fruit(): form = FruitForm() result = None if form.validate_on_submit(): fruit_name = form.fruit_name.data result = f"{fruit_name}は美味しそうですね!" return render_template("fruit.html", form=form, result=result)
この部分では、
/fruit
にアクセスされたときの動きを定義しています。render_template()
:HTMLファイルを表示し、その中にフォームと結果を渡す。@app.route("/fruit", methods=["GET", "POST"])
:フォームを表示&送信処理をするURLを設定。form = FruitForm()
:作成したフォームクラスを使ってフォームのインスタンスを作成。form.validate_on_submit()
:ページが送信された(POST)ことと「空欄禁止」を満たしていることを同時にチェックform.fruit_name.data
:ユーザーが入力したフルーツ名を取得。result
:表示用のメッセージを作成。
Flaskアプリの起動設定
if __name__ == "__main__": app.run(debug=True)
if __name__ == "__main__":
:このファイルが直接実行されたときだけ、下の処理を実行する。app.run(debug=True)
:アプリを起動。debug=True
にすると、コードを変更したときに自動で再起動してくれる。
FAQ|Flask-WTFの導入と活用に関するよくある質問
- Q1. Flask-WTFの導入時に「secret_key」は必ず必要ですか?
-
はい、Flask-WTFではCSRF保護機能が標準で有効になっており、そのトークンの生成に「secret_key」が必須です。これが設定されていないと、フォームは正しく動作しません。
- Q2. Flask-WTFのフォームクラスは複数作っても問題ありませんか?
-
問題ありません。用途ごとに異なるフォームクラスを定義することで、アプリの構造が整理され、保守性も高まります。各クラスはFlaskFormを継承して独立して動作します。
- Q3. Flask-WTFを使うとフォームのバリデーションエラーは自動で表示されますか?
-
いいえ、自動では表示されません。テンプレート側で
{{ form.field.errors }}
を使って、必要な位置にエラーメッセージを表示させる必要があります。
質問用コンタクトフォーム
この記事を書くにあたりAIを活用しています。
人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。