このガイドの目的は、かなり機能的なマイクロブログアプリケーションを開発することです。オリジナリティが完全に欠如しているため、マイクロブログアプリケーションと呼ぶことにしました。
目次
短い繰り返し
前のパートでは、ホームページ用のシンプルなテンプレートを定義し、仮想オブジェクトをまだ持っていないもののプロトタイプとして使用しました。 たとえば、ユーザーまたはレコード。
この記事では、アプリケーションに存在するギャップの1つを埋めます。 フォームの使用を検討します。
フォームは、Webアプリケーションで最も基本的なブロックの1つです。 フォームを使用すると、ユーザーはブログのエントリを残したり、アプリケーションにログインしたりできます。
この部分に従うには、マイクロブログアプリケーションは、前の記事の最後に残したものと同じでなければなりません。 アプリケーションがインストールされ動作していることを確認してください。
構成
フォームの処理には、
WTForms
ラッパーであり、Flaskアプリケーションと完全に統合される
Flask-WTF
拡張機能を使用します。
多くのFlask拡張機能には設定が必要なため、必要に応じて変更のために簡単にアクセスできるように、マイクロブログルートフォルダー内に設定ファイルを作成します。 ここから始めます(config.pyファイル):
CSRF_ENABLED = True SECRET_KEY = 'you-will-never-guess'
簡単です。これらは、
Flask-WTF
拡張機能に必要な2つの設定です。
CSRF_ENABLED
は、偽のクロスサイトリクエストの防止を有効にします。 ほとんどの場合、このオプションを有効にすると、アプリケーションがより安全になります。
SECRET_KEY
、
CSRF
有効な場合にのみ必要です。 フォーム検証で使用される暗号化トークンを作成するために使用されます。 アプリケーションを作成するときは、秘密鍵を入手するのが難しいことを確認してください。
これで設定ができましたので、Flaskにそれを読み取って使用するように指示する必要があります。 Flaskアプリケーションオブジェクトが作成された直後にこれを行うことができます。 (ファイルapp / __ init__.py):
from flask import Flask app = Flask(__name__) app.config.from_object('config') from app import views
ログインフォーム
Flask-WTF
フォームは
Form
クラスのサブクラスオブジェクトとして表されます。 フォームサブクラスは、フォームフィールドをクラスの変数として単純に定義します。
識別システムと一緒に使用されるログインフォームを作成します。 アプリケーションでサポートするログインメカニズムは、ユーザー名/パスワードの標準タイプではありません-OpenIDをログインとして使用します。 OpenIDの利点は、認証がOpenIDプロバイダーを介して渡されるため、パスワードを確認する必要がないことです。これにより、ユーザーのサイトがより安全になります。
OpenIDログインには、OpenIDという1行のみが必要です。 また、フォームに[Remember Me]チェックボックスをドロップして、ユーザーがブラウザーにCookieを設定できるようにします。これにより、ユーザーが戻ったときにユーザー名が記憶されます。
最初のフォーム(ファイルapp / forms.py)を作成します。
from flask.ext.wtf import Form from wtforms import TextField, BooleanField from wtforms.validators import Required class LoginForm(Form): openid = TextField('openid', validators = [Required()]) remember_me = BooleanField('remember_me', default = False)
クラスはそれ自体を語っていると確信しています。
Form
クラスと、必要な2つのフィールドクラス
TextField
と
BooleanField
。
インポートされた
Required
は、ユーザーが送信したデータを検証するためにフィールドにアタッチできるバリデーターです。
Required
バリデーターは、フィールドが空白で送信されなかったことを確認するだけです。
Flask-WTF
には多くのバリデーターがありますが、今後いくつかの新しいバリデーターを使用します。
フォームテンプレート
フォームを含むHTMLテンプレートも必要です。
LoginForm
なことに、作成した
LoginForm
クラスはHTMLでフォームフィールドをレンダリングする方法を知っているため、レイアウトに集中するだけです。 ログインテンプレートは次のとおりです:(app / templates / login.html file):
<!-- extend from base layout --> {% extends "base.html" %} {% block content %} <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID:<br> {{form.openid(size=80)}}<br> </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
継承演算子を介して
base.html
テンプレートを再び使用し、それを拡張していることに注意してください。 すべてのテンプレートでこれを行い、レイアウトがすべてのページで一貫していることを確認します。
通常のHTMLフォームとテンプレートにはいくつかの興味深い違いがあります。 テンプレートは、
form
テンプレート引数で割り当てたばかりのフォームクラスのインスタンスを想定しています。 今後、このテンプレートを返すビュー関数を作成するときに、このテンプレート引数の送信を処理します。
テンプレートパラメータ
form.hidden_tag()
は、CSRFが設定ファイルに含まれないように非表示フィールドに置き換えられます。 CSRFが有効な場合、このフィールドはすべてのフォームにある必要があります。
フォームのフィールドはフォームオブジェクトによって指定されます。フィールドを挿入するテンプレートの場所で引数
{{form.field_name}}
を参照するだけです。 一部のフィールドは引数を取る場合があります。 この場合、フォームに幅80文字のopenidフィールドを作成するように依頼します。
フォームクラスで送信ボタンを定義しなかったため、通常のフィールドとして定義する必要があります。 送信フィールドにはデータが含まれないため、フォームクラスで定義する必要はありません。
フォーム提出
フォームを見る前の最後のステップは、テンプレートをレンダリングするプレゼンテーション関数を書くことです。
フォームオブジェクトをテンプレートに渡すだけでよいため、これは実際には非常に簡単です。 新しいビュー関数(app / views.pyファイル)は次のとおりです。
from flask import render_template, flash, redirect from app import app from forms import LoginForm # index @app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() return render_template('login.html', title = 'Sign In', form = form)
LoginForm
クラスをインポートし、そのインスタンスを作成して、テンプレートに送信しました。 フォームフィールドを描画するために必要なのはこれだけです。
flash
インポートと
redirect
注意を払いません。 後でそれらを使用します。
別の革新は、
route
デコレータのメソッド引数です。 ここで、ビュー関数が
GET
および
POST
リクエストを受け入れることをFlaskに伝えます。 これがないと、送信は
GET
要求のみを受け入れます。 ユーザーが入力したデータを含むフォームを送信する
POST
リクエストを受け取りたい。
この段階で、アプリケーションを起動し、ブラウザでフォームを確認できます。 開始後、ビュー関数loginに関連付けたアドレスを開きます: http:// localhost:5000 / login
データを受信する部分はプログラムしていないため、送信ボタンをクリックしても効果はありません。
フォームデータの取得
Flask-WTF
が作業を容易にするもう1つの分野は、送信されたデータの処理です。 これは
login
ビュー関数の新しいバージョンで、フォームデータ(app / views.pyファイル)を検証して保存します。
@app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data)) return redirect('/index') return render_template('login.html', title = 'Sign In', form = form)
validate_on_submit
メソッドは処理全体を実行します。 フォームがユーザーに表示されたときに(つまり、ユーザーがデータを入力する前に)メソッドを呼び出した場合、ユーザーは
False
を返します。この場合、テンプレートを描画する必要があることがわかります。
validate_on_submit
がフォーム送信リクエストの一部として一緒に呼び出された場合、すべてのデータを収集し、フィールドにアタッチされたバリデーターを実行します。すべて問題なければ、データの有効性を示す
True
を返します。 これは、データをアプリケーションに含めるのに安全であることを意味します。
少なくとも1つのフィールドが検証に合格しない場合、関数は
False
を返します。これにより、ユーザーの前にフォームが再び描画され、エラーを修正できるようになります。 後で、検証が失敗したときにエラーメッセージを表示する方法を学習します。
validate_on_submit
が
True
validate_on_submit
返すと、ビュー関数はFlaskからインポートされた2つの新しい関数を呼び出します。
Flash
機能は、ユーザーに表示される次のページにメッセージを表示する簡単な方法です。 この場合、ロギングに必要なインフラストラクチャができるまでデバッグにこれを使用し、代わりに、送信されたデータを示すメッセージを表示します。
flash
、ユーザーのフィードバックを提供する本番サーバーでも非常に役立ちます。
Flashメッセージはページに自動的に表示されません。テンプレートはサイトのレイアウトに合った形式でメッセージを表示する必要があります。 すべてのテンプレートがこの機能を継承するように、ベーステンプレートにメッセージを追加します。 これは更新された基本テンプレートです(ファイルapp / templates / base.html):
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <div>Microblog: <a href="/index">Home</a></div> <hr> {% with messages = get_flashed_messages() %} {% if messages %} <ul> {% for message in messages %} <li>{{ message }} </li> {% endfor %} </ul> {% endif %} {% endwith %} {% block content %}{% endblock %} </body> </html>
メッセージの表示方法に説明が必要ないことを願っています。
ログインビューで使用した別の新しい機能は
redirect
です。 この関数は、要求されたページではなく、クライアントのWebブラウザーを別のページにリダイレクトします。 プレゼンテーション機能では、前のパートで開発したメインページへのリダイレクトを使用しました。 関数がリダイレクトで終了した場合でも、フラッシュメッセージが表示されることに注意してください。
アプリケーションを実行し、フォームがどのように機能するかを確認するのに最適な時間です。 空のopenidフィールドを持つフォームを送信して、
Required
バリデーターが送信プロセスを停止する方法を確認してください。
フィールド検証の改善
現在の状態のアプリケーションでは、無効なデータで送信されたフォームは受け入れられません。 代わりに、フォームは再び修正のためにユーザーに送信されます。 これがまさに私たちに必要なものです。
私たちが見逃したのは、フォームの何が間違っていたかのユーザーからの通知でした。 幸いなことに、
Flask-WTF
はこのタスクを簡単にします。
フィールドの検証に失敗すると、
Flask-WTF
はフォームオブジェクトに視覚的なエラーメッセージを追加します。 これらのメッセージはテンプレートで利用できるため、表示するロジックを追加するだけです。
これは、フィールド検証メッセージを含むログインテンプレートです(ファイルapp / templates / login.html):
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID:<br> {{form.openid(size=80)}}<br> {% for error in form.errors.openid %} <span style="color: red;">[{{error}}]</span> {% endfor %}<br> </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
私たちが行った唯一の変更は、openidフィールドの右側にバリデーターによって追加されたエラーメッセージを描画するループを追加することでした。 原則として、バリデーターが添付されたフィールドには、
form.errors._
としてエラーが追加され
form.errors._
。 この場合、
form.errors.openid
を使用し
form.errors.openid
。 これらのメッセージを赤で表示して、ユーザーの注意を喚起します。
OpenIDとの相互作用
実際、多くの人がすでにOpenIDをいくつか持っていることすら知らないという事実に直面します。 多くの主要なインターネットサービスプロバイダーがユーザーのOpenID認証をサポートしていることはあまり知られていません。 たとえば、Googleアカウントを持っている場合は、OpenIDを持っています。 Yahoo、AOL、Flickr、その他の多くのサービスと同様に。
頻繁に使用されるOpenIDのいずれかを使用してサイトへのユーザーアクセスを容易にするために、ユーザーがOpenIDを手動で入力する必要がないように、それらの一部にリンクを追加します。
紹介したいOpenIDプロバイダーのリストを定義することから始めましょう。 設定ファイル(config.pyファイル)でこれを行うことができます:
OPENID_PROVIDERS = [ { 'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id' }, { 'name': 'Yahoo', 'url': 'https://me.yahoo.com' }, { 'name': 'AOL', 'url': 'http://openid.aol.com/<username>' }, { 'name': 'Flickr', 'url': 'http://www.flickr.com/<username>' }, { 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }]
ログインビュー関数でこのリストを使用する方法を見てみましょう。
@app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data)) return redirect('/index') return render_template('login.html', title = 'Sign In', form = form, providers = app.config['OPENID_PROVIDERS'])
ここでは、
app.config
キーで設定を検索して設定を取得します。 リストは、テンプレート引数として
render_template
呼び出しに追加されます。
ご想像のとおり、これを終了するには別の手順を実行する必要があります。 次に、ログインテンプレート(ファイルapp / templates / login.html)でこれらのプロバイダーへのリンクを表示する方法を指定する必要があります。
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <script type="text/javascript"> function set_openid(openid, pr) { u = openid.search('<username>') if (u != -1) { // openid requires username user = prompt('Enter your ' + pr + ' username:') openid = openid.substr(0, u) + user } form = document.forms['login']; form.elements['openid'].value = openid } </script> <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID, or select one of the providers below:<br> {{form.openid(size=80)}} {% for error in form.errors.openid %} <span style="color: red;">[{{error}}]</span> {% endfor %}<br> |{% for pr in providers %} <a href="javascript:set_openid('{{pr.url}}', '{{pr.name}}');">{{pr.name}}</a> | {% endfor %} </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
これらのすべての変更に関連して、テンプレートはやや長いことが判明しました。 一部のOpenIDにはユーザー名が含まれているため、ユーザー名を要求してからOpenIDを作成するJavaScriptマジックが必要です。 ユーザーがプロバイダーのOpenIDリンクをクリックし、(オプションで)ユーザー名を入力すると、このプロバイダーのOpenIDがテキストボックスに挿入されます。

Google OpenIDリンクをクリックした後のログインページのスクリーンショット
最後の言葉
ログインフォームは大幅に進歩しましたが、実際には、ユーザーがシステムに入るために何もしていません。 私たちがしたことは、ログインプロセスのGUIに関連することだけでした。 これは、実際のログインを行う前に、ユーザーを記録できるデータベースが必要だからです。
次の部分では、データベースを作成して起動します。少し後でログインシステムを完成させますので、以下の記事の更新にご注目ください。
現在の状態のマイクロブログアプリケーションは、ここからダウンロードできます。
microblog-0.3.zip
zipファイルには、フラスコ仮想環境が含まれていないことに注意してください。 アプリケーションを開始する前に、最初の部分の指示に従って自分で作成します。
ご質問やご意見がありましたら、下に自由に残してください。
ミゲル