著者は、Write for DOnationsプログラムの一環として、寄付を受け取るためにFree and Open Source Fundを選択しました。
はじめに
テキストフィールドやテキストエリアなどのウェブフォームは、ユーザーがデータをアプリケーションに送信し、アクションを実行するためにそれを使用したり、アプリケーションに大きなテキストを送信したりすることができます。例えば、ソーシャルメディアアプリケーションでは、ユーザーが自分のページに新しいコンテンツを追加できるボックスを提供することができます。別の例として、ログインページがあります。この場合、ユーザーにユーザー名を入力するためのテキストフィールドと、パスワードを入力するためのパスワードフィールドを提供します。サーバー(この場合はFlaskアプリケーション)は、ユーザーが送信したデータを使用し、データが有効であればユーザーをログインさせるか、Invalid credentials!
のようなメッセージでユーザーに送信したデータが正しくないことを通知します。
Flaskは、Python言語でWebアプリケーションを作成するための便利なツールや機能を提供する軽量のPython Webフレームワークです。このチュートリアルでは、Webフォームの使用方法を示す小さなWebアプリケーションを構築します。このアプリケーションには、Pythonリストに保存されているメッセージを表示するためのページと、新しいメッセージを追加するためのページがあります。また、メッセージフラッシュを使用して、ユーザーが無効なデータを送信した際のエラーを通知します。
前提条件
-
ローカルのPython 3プログラミング環境を用意してください。お使いのディストリビューションのチュートリアルに従って、Python 3のローカルプログラミング環境のインストールとセットアップ方法シリーズを参照してください。このチュートリアルでは、プロジェクトディレクトリを
flask_app
と呼びます。 -
Flaskの基本的な概念、例えばルート、ビュー関数、テンプレートについて理解していること。Flaskに詳しくない場合は、FlaskとPythonを使って初めてのWebアプリケーションを作成する方法とFlaskアプリケーションでテンプレートを使用する方法をチェックしてください。
-
基本的なHTMLの概念を理解していること。背景知識については、HTMLでウェブサイトを構築する方法チュートリアルシリーズをご覧ください。
ステップ1 — メッセージの表示
このステップでは、Pythonの辞書のリストに保存されているメッセージを表示するためのインデックスページを持つFlaskアプリケーションを作成します。
まず、新しいファイル app.py
を編集用に開いてください:
app.py
ファイル内に以下のコードを追加して、単一のルートを持つFlaskサーバーを作成します:
ファイルを保存して閉じます。
このファイルでは、最初に Flask
クラスと flask
パッケージから render_template()
関数をインポートします。次に、Flask
クラスを使用して、新しいアプリケーションインスタンスを app
という名前で作成し、特別な __name__
変数を渡します。これは、Flaskが舞台裏でいくつかのパスを設定するために必要です。テンプレートのレンダリングについては、チュートリアル Flaskアプリケーションでテンプレートを使用する方法 で説明されています。
次に、messages
というグローバルなPythonリストを作成します。これにはPythonの辞書が含まれており、各辞書にはメッセージのタイトルを表す title
とメッセージの内容を表す content
の2つのキーがあります。これはデータストレージ方法の簡略化された例です。実際のシナリオでは、データを永続的に保存し、より効率的に操作できるデータベースを使用します。
Pythonリストを作成した後、@app.route()
デコレータを使用して、index()
という名前のビュー関数を作成します。この関数内で、render_template()
関数を呼び出すことを返します。これにより、Flaskに対して、ルートがHTMLテンプレートを表示する必要があることが示されます。このテンプレートにはindex.html
という名前を付け(後で作成します)、messages
という変数を渡します。この変数は、以前に宣言したmessages
リストを値として保持し、HTMLテンプレートで利用できるようにします。ビュー関数については、チュートリアルFlaskとPython 3を使って初めてのWebアプリケーションを作成する方法で説明されています。
次に、Flaskがテンプレートを検索するflask_app
ディレクトリにtemplates
フォルダを作成し、base.html
というテンプレートファイルを開きます。このファイルには、他のテンプレートがコードの重複を避けるために継承するコードが含まれています。
base.html
ファイル内に以下のコードを追加して、ナビゲーションバーとコンテンツブロックを持つ基本テンプレートを作成します。
ファイルを保存して閉じます。
この基本テンプレートには、他のテンプレートで再利用するために必要なすべてのHTMLの雛形が含まれています。title
ブロックは各ページのタイトルを設定するために置き換えられ、content
ブロックは各ページの内容で置き換えられます。ナビゲーションバーには2つのリンクがあり、1つはurl_for()
ヘルパー関数を使用してindex()
ビュー関数にリンクするインデックスページ用で、もう1つはアプリケーションに含める場合のAboutページ用です。
次に、index.html
というテンプレートを開きます。これはapp.py
ファイルで参照したテンプレートです:
以下のコードを追加してください:
ファイルを保存して閉じます。
このコードでは、base.html
テンプレートを拡張し、content
ブロックの内容を置き換えています。<h1>
見出しを使用してタイトルとしても機能させています。
この行{% for message in messages %}
では、Jinjaのfor
ループを使用して、messages
リスト内の各メッセージを順番に処理しています。メッセージのタイトルと内容を含むために<div>
タグを使用しています。タイトルは<h3>
見出しで、内容は<p>
タグで表示しています。
仮想環境が有効になっているflask_app
ディレクトリ内で、Flaskにアプリケーション(この場合はapp.py
)についてFLASK_APP
環境変数を使用して伝えます:
それでは、FLASK_ENV
環境変数をdevelopment
に設定して、開発モードでアプリケーションを実行し、デバッガにアクセスできるようにします。Flaskデバッガの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。これを行うには、以下のコマンドを使用します(Windowsではexport
の代わりにset
を使用してください):
次に、アプリケーションを実行します:
開発サーバーが稼働している状態で、ブラウザを使用して以下のURLにアクセスします:
http://127.0.0.1:5000/
インデックスページにmessages
リストのメッセージが表示されます:
これでウェブアプリケーションをセットアップし、メッセージを表示できました。次に、ユーザーが新しいメッセージをインデックスページに追加できるようにする方法が必要です。これはウェブフォームを通じて行います。次のステップでウェブフォームを設定します。
ステップ2 — フォームの設定
このステップでは、アプリケーションにユーザーが新しいメッセージをメッセージリストに追加できるページを作成します。
開発サーバーを稼働させたまま、新しいターミナルウィンドウを開いてください。
まず、app.py
ファイルを開きます:
ファイルの末尾に以下のルートを追加します:
ファイルを保存して閉じます。
この/create
ルートは、methods
パラメータにタプル('GET', 'POST')
を持ち、GET
とPOST
リクエストの両方を受け入れます。GET
とPOST
はHTTPメソッドです。デフォルトでは、データを取得するために使用されるGET
リクエストのみが受け入れられます。例えば、サーバーにインデックスページやAboutページを要求する場合です。POST
リクエストは、特定のルートにデータを送信するために使用され、サーバー上のデータが変更されることがよくあります。
この例では、GET
リクエストを使用してcreate
ページを要求します。Createページには、入力フィールドと送信ボタンを持つウェブフォームがあります。ユーザーがウェブフォームに記入して送信ボタンをクリックすると、POST
リクエストが/create
ルートに送信されます。そこでリクエストを処理し、ユーザーが空のフォームを送信していないことを確認するために送信されたデータを検証し、messages
リストに追加します。
create()
ビュー関数は現在、通常のGETリクエストを受け取ったときにcreate.html
というテンプレートをレンダリングするだけです。このテンプレートを作成し、次のステップでPOST
リクエストを処理するために関数を編集します。
create.html
という新しいテンプレートファイルを開きます:
次のコードを追加します:
ファイルを保存して閉じます。
このコードでは、base.html
テンプレートを拡張し、content
ブロックをページのタイトルとして機能する<h1>
見出しで置き換えています。<form>
タグでは、method
属性をpost
に設定し、フォームデータがPOST
リクエストとしてサーバーに送信されるようにしています。
フォーム内には、title
という名前のテキスト入力フィールドがあります。これは、アプリケーション内でタイトルのフォームデータにアクセスする際に使用する名前です。<input>
タグには、{{ request.form['title'] }}
というvalue
を設定しています。これにより、何か問題が発生した場合でもユーザーが入力したデータが失われないようになっています。例えば、ユーザーが必須のcontent
テキストエリアを埋め忘れた場合、リクエストがサーバーに送信され、エラーメッセージがレスポンスとして返されますが、タイトルのデータはrequest
グローバルオブジェクトに保存され、request.form['title']
を通じてアクセスできます。
タイトル入力フィールドの後に、前述の理由と同じく{{ request.form['content'] }}
の値を持つcontent
という名前のテキストエリアを追加しています。
最後に、フォームの末尾に送信ボタンがあります。
開発サーバーが実行中の状態で、ブラウザを使用して/create
ルートに移動します。
http://127.0.0.1:5000/create
「新しいメッセージを追加」ページが表示され、メッセージのタイトル用の入力フィールド、メッセージの内容用のテキストエリア、そして送信ボタンが表示されます。
このフォームは、create()
ビュー関数に POST
リクエストを送信します。ただし、この関数にはまだ POST
リクエストを処理するコードがないため、フォームに記入して送信しても何も起こりません。次のステップでは、フォームが送信されたときに受信する POST
リクエストを処理します。送信されたデータが有効かどうか(空でないか)を確認し、メッセージのタイトルと内容を messages
リストに追加します。
ステップ 3 — フォームリクエストの処理
このステップでは、アプリケーション側でフォームリクエストを処理します。前のステップで作成したフォームを介してユーザーが送信するフォームデータにアクセスし、それをメッセージのリストに追加します。また、メッセージフラッシュを使用して、無効なデータを送信したユーザーに通知します。フラッシュメッセージは一度だけ表示され、次のリクエストで消えます(例えば別のページに移動した場合)。
app.py
ファイルを編集用に開きます:
まず、Flask フレームワークから以下をインポートします:
- 前のステップで構築した HTML フォームを介して送信される着信リクエストデータにアクセスするためのグローバル
request
オブジェクト。 url_for()
関数を使ってURLを生成します。flash()
関数を使ってリクエストが処理された際にメッセージを表示します(ユーザーに全てが順調であることを通知したり、送信データが無効な場合に問題を通知します)。redirect()
関数を使ってクライアントを別の場所にリダイレクトします。
これらのインポートをファイルの最初の行に追加します:
flash()
関数は、クライアントのブラウザセッションにフラッシュメッセージを保存します。これにはシークレットキーの設定が必要です。このシークレットキーはセッションを保護するために使用され、Flaskが新しいメッセージページからインデックスページへと移動する際に、リクエスト間で情報を記憶することを可能にします。ユーザーはセッションに保存された情報にアクセスできますが、シークレットキーを持っていない限り変更することはできません。そのため、シークレットキーへのアクセスを誰にも許可しないようにしてください。詳細についてはFlaskのセッションに関するドキュメントを参照してください。
秘密鍵は長いランダムな文字列であるべきです。os
モジュールのos.urandom()
メソッドを使って秘密鍵を生成することができます。このメソッドは、暗号化に適したランダムなバイト列の文字列を返します。これを使ってランダムな文字列を取得するには、新しいターミナルを開き、以下のコマンドを使ってPythonの対話型シェルを開いてください:
Pythonの対話型シェルで、標準ライブラリからos
モジュールをインポートし、以下のようにos.urandom()
メソッドを呼び出します:
次のような文字列が得られます:
Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'
この文字列を秘密鍵として使用できます。
秘密鍵を設定するには、app.config
オブジェクトを通じてアプリケーションにSECRET_KEY
設定を追加します。app
定義の直後、messages
変数を定義する前に直接追加します:
次に、create()
ビュー関数を以下のように正確に修正します:
if
文で、リクエストがPOST
リクエストである場合にのみ、後続のコードが実行されるように、request.method == 'POST'
と比較して確認します。
その後、request.form
オブジェクトから送信されたタイトルとコンテンツを抽出します。このオブジェクトはリクエスト内のフォームデータにアクセスできます。タイトルが提供されていない場合、条件if not title
が満たされます。その場合、flash()
関数を使用してユーザーにタイトルが必要であることを通知するメッセージを表示します。これにより、メッセージがflashed messagesリストに追加されます。後ほど、これらのメッセージをbase.html
テンプレートの一部としてページに表示します。同様に、コンテンツが提供されていない場合、条件elif not content
が満たされます。その場合、'Content is required!'
メッセージをflashed messagesリストに追加します。
タイトルとメッセージのコンテンツが適切に送信された場合、messages.append({'title': title, 'content': content})
を使用して、ユーザーが提供したタイトルとコンテンツを含む新しい辞書をmessages
リストに追加します。その後、redirect()
関数を使用してユーザーをインデックスページにリダイレクトします。インデックスページへのリンクにはurl_for()
関数を使用します。
ファイルを保存して閉じます。
次に、ウェブブラウザを使用して/create
ルートに移動します。
http://127.0.0.1:5000/create
好きなタイトルとコンテンツをフォームに入力してください。フォームを送信すると、新しいメッセージがインデックスページにリストされます。
最後に、flashed messagesを表示し、「新しいメッセージ」ページへのリンクをナビゲーションバーに追加して、この新しいページに簡単にアクセスできるようにします。ベーステンプレートファイルを開きます。
ファイルを編集し、<nav>
タグ内のFlaskAppリンクの後に新しい<a>
タグを追加してください。次に、content
ブロックの直上に新しいfor
ループを追加し、ナビゲーションバーの下にフラッシュされたメッセージを表示します。これらのメッセージは、Flaskが提供する特別なget_flashed_messages()
関数で利用可能です。そして、各メッセージにalert
というクラス属性を追加し、<style>
タグ内にいくつかのCSSプロパティを設定します:
ファイルを保存して閉じ、その後ブラウザでhttps://127.0.0.1:5000
を再読み込みしてください。ナビゲーションバーには、/create
ルートにリンクする「Create」アイテムが表示されます。
フラッシュメッセージの動作を確認するために、「Create」ページに移動し、2つのフィールドを埋めずにSubmitボタンをクリックしてください。以下のようなメッセージが表示されます:
インデックスページに戻ると、ナビゲーションバーの下に表示されていたフラッシュメッセージは消えています。これらはベーステンプレートの一部として表示されているにもかかわらずです。もしこれらがフラッシュメッセージでなければ、インデックスページにも表示されるでしょう。なぜなら、インデックスページもベーステンプレートを継承しているからです。
フォームにタイトルだけで内容がない状態で送信してみてください。「内容は必須です!」というメッセージが表示されます。ナビゲーションバーのFlaskAppリンクをクリックしてインデックスページに戻り、その後「戻る」ボタンをクリックして作成ページに戻ると、メッセージ内容がまだ残っていることがわかります。これは「戻る」ボタンをクリックした場合にのみ機能し、前回のリクエストを保存するためです。ナビゲーションバーのCreateリンクをクリックすると新しいリクエストが送信され、フォームがクリアされるため、フラッシュメッセージは消えます。
ユーザーの入力を受け取り、それを検証し、データソースに追加する方法を学びました。
注意:
messages
リストに追加したメッセージは、サーバーが停止すると消えてしまいます。これはPythonのリストがメモリ内にのみ保存されるためです。メッセージを永続的に保存するには、SQLiteのようなデータベースを使用する必要があります。PythonでSQLiteを使用する方法については、Python 3でsqlite3モジュールを使用する方法を参照してください。
結論
インデックスページに表示されるメッセージリストにユーザーがメッセージを追加できるFlaskアプリケーションを作成しました。Webフォームを作成し、ユーザーがフォームを介して送信するデータを処理し、メッセージリストに追加しました。また、無効なデータが送信された場合にユーザーに通知するためにフラッシュメッセージを使用しました。
Flaskについてもっと読みたい場合は、Flaskシリーズの他のチュートリアルをチェックしてください。
Source:
https://www.digitalocean.com/community/tutorials/how-to-use-web-forms-in-a-flask-application