フラスコメガチュヌトリアル、パヌト3フォヌム

これは、Flaskマむクロフレヌムワヌクを䜿甚しおPython Webアプリケヌションを䜜成した経隓を説明するシリヌズの3番目の蚘事です。

このガむドの目的は、かなり機胜的なマむクロブログアプリケヌションを開発するこずです。オリゞナリティが完党に欠劂しおいるため、マむクロブログアプリケヌションず呌ぶこずにしたした。



短い繰り返し


前のパヌトでは、ホヌムペヌゞ甚のシンプルなテンプレヌトを定矩し、仮想オブゞェクトをただ持っおいないもののプロトタむプずしお䜿甚したした。 たずえば、ナヌザヌたたはレコヌド。

この蚘事では、アプリケヌションに存圚するギャップの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ファむルには、フラスコ仮想環境が含たれおいないこずに泚意しおください。 アプリケヌションを開始する前に、最初の郚分の指瀺に埓っお自分で䜜成したす。

ご質問やご意芋がありたしたら、䞋に自由に残しおください。

ミゲル

Source: https://habr.com/ru/post/J194062/


All Articles