Flask入門|WTFormsの基本構文と使い方をマスターしよう【チャプター4-03】

ながみえ

一つ前のページではフォームの基本について学習しました。

今回は WTForms について見ていきましょう。

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:アプリ開発編

Webアプリケーションでユーザーから情報を入力してもらう場面はよくあります。

たとえば名前や年齢、メールアドレスを入力してもらったり、アンケートのようなフォームを作ったりすることもあるでしょう。

Flaskではこのようなフォームを手軽に扱えるようにするためのライブラリがいくつか存在します。

その中でも、今回紹介する「WTForms(ダブルティーフォームズ)」はFlaskと非常に相性がよく、効率的にフォームを作成・管理することができます。

この記事ではWTFormsの基本的な使い方を学び、フォームの作成からテンプレートへの組み込みまでの流れを、具体的なコード例と共に丁寧に解説していきます。

本記事は 有料記事(100円)ですが、現在は期間限定で無料公開中です。

<<前のページ

Flaskの記事一覧

次のページ>>

WTFormsの役割と導入方法の解説

【Python】勉強猫がノートパソコンを前にして学習を始める様子。記事内の学習スタート用イラスト

Flaskでフォームを扱うならWTFormsを使おう!

WTForms はPythonでWebフォームを扱うためのライブラリです。

Chapter4-2で紹介したように、Flask単体でもフォームを使うことはできます。しかしWTFormsを使うと次のようなメリットがあります。

  • 入力フィールドをPythonのクラスとして定義できる
  • 入力チェック(バリデーション)を簡単に行える
  • HTMLテンプレートへの組み込みがシンプルになる

言葉の意味
WTFormsの「WT」は「Web Template」の略とされ、HTMLテンプレートと連携するためのフォーム機能という意味が込められています。

Flaskとの関係
WTFormsはFlaskに標準で組み込まれているわけではありませんが、非常に連携しやすく、「Flask-WTF」という統合ラッパーを使えばさらに便利になります(これについてはChapter4-7で解説します)。

復習しよう
【Python入門】初心者のためのクラス入門|initとインスタンスの基本を解説【レッスン5-1】
【Python入門】初心者のためのクラス入門|initとインスタンスの基本を解説【レッスン5-1】

WTFormsを使い始める準備とpipでのインストール手順

WTFormsは外部ライブラリのため、最初にインストールが必要です。以下のコマンドを使ってインストールしましょう。

pip install wtforms

インストールが完了したら、以下のようにPythonコード内でインポートして使う準備が整います。

from wtforms import Form
from wtforms.fields import StringField, IntegerField  # など

WTFormsで使う基本構文と主要フィールド紹介

WTFormsを使うためには、まず Formクラスを継承した自作フォームクラス を作成します。

復習しよう
【Python入門】クラス継承でコードを整理しよう【レッスン5-5】
【Python入門】クラス継承でコードを整理しよう【レッスン5-5】

フィールド(名前、年齢などの入力欄)は、wtforms.fieldsに入っているクラス を使って定義します。

WTFormsのフォーム定義方法を理解しよう

基本構文は以下の通りです。

class フォーム名(Form):
    フィールド名 = フィールドクラス('ラベル', オプション引数)

例えば、以下のように使用します。

class UserInfoForm(Form):
    name = StringField('名前: ', render_kw={"placeholder": "(例)フラスク太郎"})
    age = IntegerField('年齢: ', default=20)

ここでは、nameには文字列を入力させるためのフィールドクラス:StringField を使い、ラベルには「名前:」を表示しています。

render_kwはHTMLの属性(placeholderなど)を追加するための辞書です。

これをブラウザに表示させると以下のようになります。

初心者が押さえるべき定番フィールド一覧

代表的なフィールドクラスを一覧で紹介します。

これらを全て覚える必要は全くありません。どのような種類のフォームがあるかだけを覚えておき、必要に応じて調べて使う習慣を身につけましょう。

フィールドクラス説明
StringField文字列を入力する欄
IntegerField数値を入力する欄
PasswordFieldパスワード入力欄
DateField日付入力欄
RadioField選択肢(ラジオボタン)
SelectFieldプルダウン形式の選択欄
BooleanFieldチェックボックス
TextAreaField複数行テキスト欄
EmailFieldメールアドレス入力欄
SubmitField送信ボタン

HTMLにフォームを組み込む方法

定義したフォームクラスをHTMLテンプレートで表示する方法を紹介します。

この画像の1行目を表示するには、「名前:」というラベルと入力欄をそれぞれ指定する必要がります。

ラベル表示の基本構文

ラベル表示の基本構文は以下の通りです。

{{ form.フィールド名.label }}

今回の場合は「{{ form.name.label }}」と記入することになります。

フィールド表示の基本構文

入力欄表示の基本構文は以下の通りです。

{{ form.フィールド(引数) }}

今回の場合は「{{ form.name(size=20) }}」と記入することになります。

【Python】勉強猫がノートパソコンを見ながら考え込む様子。記事内の休憩用イラスト

実用的な入力フォームのサンプルコードとその解説

実際のコードを使って、WTFormsを使ったアプリケーションがどのように動くかを見ていきましょう。

これから紹介する5つのコードをコピーして、以下の階層になるよう保存してください。

保存フォルダ
├── chapter4-3.py
├── forms.py
└── templates/(フォルダ)
    ├── base.html
    ├── enter.html
    └── result.html

保存後に「chapter4-3.py」を実行すると下図の左側のように表示され、入力欄記入後に送信ボタンを押すと右側のように表示されるはずです。

アプリケーションファイル

from flask import Flask, render_template, request
app = Flask(__name__)

# --- ルーティング ---
from forms import UserInfoForm # forms.pyのUserInfoFormクラスをインポート

# ユーザー情報入力
@app.route('/', methods=['GET','POST']) # このURLにGETまたはPOSTリクエストが来たときに実行
def show_Enter():
    # フォームの作成
    form = UserInfoForm(request.form) # インスタンスを生成
    if request.method == 'POST':      # もしリクエストがPOSTなら(フォームが送信されたら)
        return render_template('result.html',form=form) # formインスタンスをresult.htmlに渡して表示
    return render_template('enter.html', form=form)     # formインスタンスをenter.htmlに渡して表示
    # request.formはフォームデータを格納する辞書オブジェクト
    # これを引数としてUserInfoFormに渡すことで、送信された値がフィールドに反映される

# --- 実行 ---
if __name__ == '__main__':
    app.run()
  • request.formでフォームからの入力を受け取り、それをフォームクラスに渡します。
  • render_template()でテンプレートへフォームオブジェクトを渡しています。

フォームの定義ファイル

from wtforms import Form     # wtformsモジュールのForm基底クラスをインポート
from wtforms.fields import(  # wtforms.fieldsの各種クラスをインポート
    StringField, IntegerField, PasswordField, DateField,
    RadioField, SelectField, BooleanField, TextAreaField,
    EmailField, SubmitField
)

# ユーザー情報クラス
class UserInfoForm(Form): # Formクラスを継承したUserInfoFormクラスの定義
    # 名前:文字列入力
    name = StringField('名前: ', render_kw={"placeholder": "(例)フラスク太郎"})
    # 年齢:整数値入力
    age = IntegerField('年齢: ', default=20)
    # パスワード:パスワード入力
    password = PasswordField('パスワード: ')
    # 確認用:パスワード入力
    confirm_password = PasswordField('パスワード確認: ')
    # Email:メールアドレス入力
    email = EmailField('メールアドレス: ')
    # 生年月日:日付入力
    birthday = DateField('生年月日: ', format="%Y-%m-%d", render_kw={"placeholder": "yyyy/mm/dd"})
    # 性別
    gender = RadioField('性別: ', choices=[('man', '男性'), ('woman', '女性')], default='man')
    # 出身地域:セレクトボックス
    area = SelectField('出身地域: ',choices=[('east', '東日本'), ('west', '西日本')])
    # 既婚:真偽値入力
    is_married = BooleanField('既婚?: ')
    # メッセージ:複数行テキスト
    note = TextAreaField('備考: ')
    # ボタン
    submit = SubmitField('送信')

このクラスにより、テンプレート側ではform.nameのように呼び出せるようになります。

ベーステンプレート

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>WTForms</title>
</head>
<body>
    {% block title %} タイトル {% endblock %}
    <hr />
    {% block content %} 内容 {% endblock %}
</body>
</html>

このファイルはテンプレートの共通部分を定義しています。

enter.htmlresult.htmlで継承されて使われます。

復習しよう
Flask入門|テンプレートの継承を理解しよう【チャプター2-02】
Flask入門|テンプレートの継承を理解しよう【チャプター2-02】

入力テンプレート

{% extends "base.html" %}

{% block title %}
    <h1>WTForm:入力</h1>
{% endblock %}

{% block content %}
    <form method="POST">
    {#  {{ form.フィールド.label }}        {{ form.フィールド(引数) }} #}
        {{ form.name.label }}             {{ form.name(size=20) }}<br>
        {{ form.age.label }}              {{ form.age() }}<br>
        {{ form.password.label }}         {{ form.password(size=20) }}<br>
        {{ form.confirm_password.label }} {{ form.confirm_password(size=20) }}<br>
        {{ form.email.label }}            {{ form.email(placeholder="xxxx@example.com" ) }}<br>
        {{ form.birthday.label }}         {{ form.birthday() }}<br>
        {{ form.gender.label }}           {{ form.gender() }}<br>
        {{ form.area.label }}             {{ form.area() }}<br>
        {{ form.is_married.label }}       {{ form.is_married() }}<br>
        {{ form.note.label }}             {{ form.note(style="height:100px; width:150px") }}<br>
        {{ form.submit() }}
    </form>
{% endblock %}
  • 各フィールドはラベルと入力欄をセットで表示しています。
  • 見やすくするために半角スペースを入れて位置を揃えています。(揃えなくても問題ない)
  • sizeplaceholderなどの属性もここで指定可能。

結果テンプレート

{% extends "base.html" %}

{% block title %}
    <h1>WTForm:結果</h1>
{% endblock %}

{% block content %}
    <ul>
        <li>名前:{{form.name.data}}</li>
        <li>年齢:{{form.age.data}}</li>
        <li>パスワード:{{form.password.data}}</li>
        <li>Email:{{form.email.data}}</li>
        <li>生年月日:{{form.birthday.data}}</li>
        <li>性別:{{form.gender.data}}</li>
        <li>地域:{{form.area.data}}</li>
        <li>既婚:{{form.is_married.data}}</li>
        <li>備考:{{form.note.data}}</li>
    </ul>
{% endblock %}

.dataでフォームに入力された値を取得し、表示しています。

{{ form.フィールド名.data }}

まとめ

この記事ではWTFormsの基礎を学びました。

フォームをPythonのコードで定義し、HTMLテンプレートと連携させることで、柔軟で拡張性のある入力画面を作成できるようになります。

  • WTFormsはPythonコードでフォーム構成を管理できるライブラリ
  • 代表的なフィールドには、文字列、数値、パスワード、選択肢など多くの種類がある
  • Flaskのテンプレートエンジンと相性が良く、{{ form.xxx }}の形でHTMLに表示可能

次回は、フォームの入力内容をチェックする「バリデーション」について学んでいきましょう。

ここまでの知識を土台に、さらに実用的なフォーム処理ができるようになります!

練習問題:WTFormsの基本的なフォームクラスとフィールドを使ってみよう

【Python】勉強猫がノートパソコンに向かい、練習問題に挑戦する様子。記事内の休憩用イラスト

この問題では、WTFormsを使って「フィードバックフォーム」を作成します。

Pythonファイル(chapter4-3-2.pyforms.py)は既に用意されていますので、それを参考にしながら、必要なHTMLテンプレートファイルを作成してください。

フォームの入力項目には「名前」「満足度(選択式)」「コメント」があり、送信ボタンを押すとその内容が別のページに表示される仕組みを作成します。

フォームの定義にはFormクラスの継承を使い、各フィールドはStringFieldSelectFieldTextAreaFieldなどを用います。

テンプレートファイルは、1つ目に「フォーム入力ページ」、2つ目に「送信結果を表示するページ」の2つを作成してください。

from flask import Flask, render_template, request
from forms import FeedbackForm  # フォームクラスをインポート

app = Flask(__name__)

# トップページ:フォームの表示と結果の処理
@app.route("/", methods=["GET", "POST"])
def index():
    form = FeedbackForm(request.form)  # フォームのインスタンスを作成

    if request.method == "POST":
        # POSTメソッドの場合は、入力結果をresult.htmlに渡す
        return render_template("result.html", form=form)

    # 初回アクセス時やGETメソッドの場合は入力フォームを表示
    return render_template("index.html", form=form)

if __name__ == "__main__":
    app.run(debug=True)
from wtforms import Form
from wtforms.fields import StringField, SelectField, TextAreaField, SubmitField

# フィードバックフォームの定義
class FeedbackForm(Form):
    # 名前:文字列の入力フィールド
    name = StringField('お名前:', render_kw={"placeholder": "例)山田太郎"})

    # 満足度:選択式(プルダウン)
    satisfaction = SelectField(
        'サービスの満足度:',
        choices=[('good', '良い'), ('normal', '普通'), ('bad', '悪い')]
    )

    # コメント:複数行テキスト入力
    comment = TextAreaField('ご意見・ご感想:', render_kw={"placeholder": "自由にご記入ください"})

    # 送信ボタン
    submit = SubmitField('送信する')

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. templates/index.html を作成し、以下を満たすこと
    • form.name.labelform.name(size=30)を使って名前入力欄を表示
    • form.satisfaction.labelform.satisfaction()を使って選択式満足度を表示(良い、普通、悪い)
    • form.comment.labelform.comment(rows=5, cols=40)を使ってコメント欄を表示
    • form.submit()で送信ボタンを表示
  2. templates/result.html を作成し、以下を満たすこと
    • form.name.data, form.satisfaction.data, form.comment.dataを使って入力結果を表示

ただし、以下のような実行結果となるコードを書くこと。

正解コード

例えば、以下のようなプログラムが考えられます。

Q
正解コード
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>フィードバックフォーム</title>
</head>
<body>
    <h1>フィードバックをお願いします</h1>
    <form method="POST">
        <!-- WTFormsで定義したフィールドのラベルと入力欄を表示 -->
        {{ form.name.label }} {{ form.name(size=30) }}<br><br>

        {{ form.satisfaction.label }} {{ form.satisfaction() }}<br><br>

        {{ form.comment.label }}<br>
        {{ form.comment(rows=5, cols=40) }}<br><br>

        {{ form.submit() }}
    </form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>送信結果</title>
</head>
<body>
    <h1>送信ありがとうございました!</h1>
    <ul>
        <!-- フォームで入力されたデータを表示 -->
        <li>お名前:{{ form.name.data }}</li>
        <li>満足度:{{ form.satisfaction.data }}</li>
        <li>コメント:{{ form.comment.data }}</li>
    </ul>
</body>
</html>

正解コードの詳細解説

正解コードをブロックごとに分割して解説します。

Q
正解コード(index.html)の詳細解説

HTML基本構造

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>フィードバックフォーム</title>
</head>
  • <!DOCTYPE html>:このファイルがHTML5形式であることを指定しています。
  • <html lang="ja">:HTML文書の言語が日本語であることを示します。
  • <meta charset="UTF-8">:文字コードとしてUTF-8を使う指定。日本語が正しく表示されるようになります。
  • <title>:ブラウザのタブなどに表示されるページのタイトル。

見出しとフォームタグの開始

<body>
    <h1>フィードバックをお願いします</h1>
    <form method="POST">
  • <h1>:ページの見出しです。
  • <form method="POST">:フォームのデータを送信する方法を指定します。ここではPOST(データを送信する際によく使う)を使います。

名前フィールドの表示

{{ form.name.label }} {{ form.name(size=30) }}<br><br>
  • {{ form.name.label }}forms.pyで定義したnameフィールドのラベル(=「お名前:」)を表示します。
  • {{ form.name(size=30) }}:テキスト入力欄を表示します。size=30は入力欄の幅を指定しています。

満足度(プルダウン)フィールドの表示

{{ form.satisfaction.label }} {{ form.satisfaction() }}<br><br>
  • form.satisfaction.labelSelectFieldで定義したラベル(=「サービスの満足度:」)を表示します。
  • form.satisfaction():プルダウンメニュー(選択欄)を表示します。

コメント(複数行入力)フィールドの表示

{{ form.comment.label }}<br>
{{ form.comment(rows=5, cols=40) }}<br><br>
  • form.comment.label:コメント入力欄のラベル(=「ご意見・ご感想:」)を表示します。
  • form.comment(rows=5, cols=40):縦5行、横40文字分のサイズでテキストエリアを表示します。

送信ボタンの表示とフォームの終了

{{ form.submit() }}
</form>
</body>
</html>
  • form.submit():送信ボタンを表示します。ボタンのラベルは「送信する」と定義されています。
  • </form>:フォームの終わりです。
Q
正解コード(result.html)の詳細解説

HTML構造の基本

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>送信結果</title>
</head>

上記はindex.htmlと同様に、HTMLの文書構造と文字コード、言語を指定する部分です。

送信完了メッセージ

<body>
    <h1>送信ありがとうございました!</h1>

<h1>:ユーザーがフォームを送信した後に表示される感謝のメッセージです。

入力内容の表示

<ul>
    <li>お名前:{{ form.name.data }}</li>
    <li>満足度:{{ form.satisfaction.data }}</li>
    <li>コメント:{{ form.comment.data }}</li>
</ul>
  • <ul>:リストを作るタグです(順序なしリスト)。
  • {{ form.フィールド名.data }}:各入力欄に入力されたデータを取得して表示します。
  • form.comment.data:コメント欄に入力された内容
  • form.name.data:名前欄に入力された内容
  • form.satisfaction.data:選択した満足度(goodなど)

<<前のページ

Flaskの記事一覧

次のページ>>

FAQ|WTFormsの使い方に関するよくある質問

Q
Q1. WTFormsのフィールドはどのように選べばいいですか?

用途に合わせて選ぶのが基本です。たとえば文字入力ならStringField、数値ならIntegerField、複数選択肢から選ぶならSelectFieldなど、入力内容に合ったフィールドを使いましょう。

Q
Q2. WTFormsでフォームを定義するクラスはどこに書けばいいですか?

一般的には、Flaskプロジェクト内のforms.pyという別ファイルに定義するのがおすすめです。アプリケーションの見通しがよくなり、コードの管理も楽になります。

Q
Q3. HTMLにフォームを表示する際、WTFormsでラベルや入力欄にCSSを適用できますか?

はい、WTFormsはフォームの各フィールドに属性(classstyleなど)を渡すことができるため、テンプレート内で自由に装飾できます。

質問用コンタクトフォーム

この記事を書くにあたりAIを活用しています。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。

記事URLをコピーしました