Flask實(shí)踐Step by Step -- Web表單

Flask開發(fā)環(huán)境配置
Flask快速入門
Flask實(shí)踐Step by Step -- 'Hello World'
Flask實(shí)踐Step by Step -- 模板
Flask實(shí)踐Step by Step -- Web表單

Flask Web Forms

上一節(jié)我們定義了一個(gè)簡(jiǎn)單的模板笼痛,并看到了實(shí)際運(yùn)行的效果扒秸,接下來我們來看一下Web表單是如何
工作的,Web表單是Web應(yīng)用程序的基礎(chǔ)控件,使用表單可以使用用戶寫博客,進(jìn)行登錄等

配置

為了使用表單,我們需要使用Flask的一個(gè)擴(kuò)展插件 Flask-WTF 需要先安裝 pip install flask-wtf ,
許多Flask擴(kuò)展需要很多的配置啦逆,我需要一個(gè)配置文件來進(jìn)行管理 config.py

WTF_CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'

配置文件中的內(nèi)容非常簡(jiǎn)單,需要兩項(xiàng)設(shè)置即可笛洛,WTF_CSRF_ENABLED設(shè)置會(huì)激活跨站訪問保護(hù)
這個(gè)設(shè)置在這個(gè)版本中Flask-WTF是默認(rèn)打開的夏志,為了更安全我們這里還是顯示的設(shè)置為 True
SECRECT_KEY的設(shè)置只有當(dāng)WTF_CSRF_ENABLED為true時(shí)才會(huì)需要,為表單驗(yàn)證創(chuàng)建一個(gè)密碼
token苛让,這個(gè)key值盡量設(shè)置的復(fù)雜一些
接下來就需要Flask讀取相關(guān)的配置沟蔑,并且使用這些配置,在Flask的應(yīng)用程序創(chuàng)建之后(file app/__init__.py)

from flask import Flask

app = Flask(__name__)
app.config.from_object('config')

from app import views

用戶登錄表單

Flask-WTF的表單是一個(gè)集成基類Form的一個(gè)類狱杰,現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)登錄的表單瘦材,需要用到身份認(rèn)證系統(tǒng)
登錄機(jī)制不是標(biāo)準(zhǔn)的 用戶名/密碼 模式,我們?cè)谶@里引入了 OpendID仿畸,OpenID本身已經(jīng)提供了
很好的驗(yàn)證食棕,我們就不在需要驗(yàn)證密碼了,這樣可以使網(wǎng)站更安全,需要安裝OpenID pip install flask-openid
使用OpenID登錄只需要一個(gè)字符串错沽,我們還提供了一個(gè) 'remember me' 選擇框簿晓,用戶可以選擇是否需要瀏覽器在cookie中記住
用戶的選擇
寫第一個(gè)表單 (file app/forms.py)

from flask.ext.wtf import Form
from wtforms import StringField,BooleanField
from wtforms.validators import DataRequired

class LoginForm(Form):
    openid = StringField('openid',validators=[DataRequired()])
    remember_me = BooleanField('remember_me',default=False)

很簡(jiǎn)單的一個(gè)類,繼承Form兩個(gè)字段千埃,StringFieldBooleanField,DataRequired是一個(gè)驗(yàn)證器
一個(gè)方法和一個(gè)字段綁定憔儿,這個(gè)DataRequired驗(yàn)證器只是簡(jiǎn)單的驗(yàn)證提交的輸入內(nèi)容,這Flask-WTF中還有很多
驗(yàn)證器放可,后續(xù)會(huì)繼續(xù)介紹

表單模板

我們需要一個(gè)模板來生成HTML的表單谒臼,我們需要?jiǎng)?chuàng)建一個(gè)新的模板 (file app/templates/login.html)

{% extends "base.html" %}

{% block content %}
  <h1>Sign in</h1>
  <form class="" action="" name="login" method="post">
    {{form.hidden_tag()}}
    <p>
      Please enter your OpenID:<br>
      {{ form.openid(size=80) }}
    </p>
    <p>
      {{ form.remember_me }} Remember Me
    </p>
    <p>
      <input type="button" value="Sign in" type="submit">
    </p>
  </form>
{% endblock %}

這個(gè)模板中同樣是繼承base.html,這個(gè)模板和普通的HTML頁面的表單還是有一些區(qū)別的,需要
視圖中對(duì)應(yīng)的方法來血染這個(gè)模板耀里,form.hidden_tag()會(huì)被HTML中的隱藏的域來取代蜈缤,這個(gè)參數(shù)
需要把CSRF設(shè)置為Enabled狀態(tài)

表單視圖

我們需要一個(gè)視圖方法來渲染這個(gè)模板(file app/views.py)

from flask import render_template,flash,redirect
from app import app
from .forms import LoginForm

#index view function...

@app.route('/login',methods=['GET','POST'])
def login():
    form = LoginForm()
    return render_template('login.html',
                            title="Sign in",
                            form=form)

需要引入 LoginForm這類,然后實(shí)例化备韧,將這個(gè)實(shí)例化對(duì)象作為參數(shù)傳入到模板中,我們還引入了
flashredirect,可以暫時(shí)忽略這兩個(gè)引用劫樟,以后我們會(huì)用到,在裝飾器中我們加入了 methods
作為參數(shù),告訴Flask我們的這個(gè)方法接收 GET和POST請(qǐng)求叠艳,保存運(yùn)行奶陈,打開瀏覽器 訪問 http://127.0.0.1:5000/login
看一下實(shí)際的效果,暫時(shí)我們還沒有處理接收數(shù)據(jù)的處理附较,所以現(xiàn)在點(diǎn)擊提交按鈕會(huì)沒有任何反饋

接收數(shù)據(jù)

Flask-WTF能夠很容易處理從客戶端發(fā)來的數(shù)據(jù)吃粒,我們需要修改一下 login的方法(file app/views.py)

@app.route('/login',methods=['GET','POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for OpenID=""%s",remember_me=%s'%
                (form.openid.data,str(form.remember_me.data)))
        return redirect('/index')
    return render_template('login.html',
                            title="Sign in",
                            form=form)

方法 validate_on_submit會(huì)處理所有的表單的處理工作,表單展示給用戶時(shí)會(huì)調(diào)用這個(gè)方法此時(shí)會(huì)返回 False
當(dāng)提交請(qǐng)求時(shí)拒课,這個(gè)方法會(huì)接收所有的數(shù)據(jù)徐勃,驗(yàn)證數(shù)據(jù)的合法性,如果驗(yàn)證全部正確早像,這個(gè)方法會(huì)返回True僻肖,只要有一個(gè)
參數(shù)驗(yàn)證不通過,這個(gè)方法就會(huì)返回 False卢鹦,稍后我們會(huì)展示如何給用戶展示錯(cuò)誤信息臀脏,當(dāng) validate_on_submit返回True
時(shí),方法 flash會(huì)展示一個(gè)快速的信息冀自,在調(diào)到下一個(gè)頁面之前揉稚,這個(gè)flash的信息不回顯示在頁面中,我們需要修改模板信息
來顯示這個(gè)信息(file app/templates/base.html)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    {% if title %}
    <title>{{ title }} - microblog</title>
    {% else %}
    <title>Welcome to microblog</title>
    {% endif %}
  </head>
  <body>
    <div>
      Microblog : <a href="/index">Home</a>
    </div>
    <hr>
    {% with messages = get_flashed_messages()%}
      {% if messages %}
        <ul>
          {% for msg in messages %}
            <li>{{ msg }}</li>
          {% endfor %}
        </ul>
      {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>
</html>

方法get_flashed_messages會(huì)接收flash方法發(fā)送來的消息熬粗,并展示出來搀玖,在視圖方法中我們還使用另一個(gè)
方法 redirect,這個(gè)方法會(huì)重定向到另一網(wǎng)頁地址

改進(jìn)數(shù)據(jù)的驗(yàn)證

當(dāng)用戶的輸入的信息有誤時(shí),希望能夠提供給用戶友好的錯(cuò)誤的信息提示驻呐,我們修改一下login的模板(file app/templates/login.html)

{% extends "base.html" %}

{% block content %}
  <h1>Sign in</h1>
  <form class="" action="" name="login" method="post">
    {{form.hidden_tag()}}
    <p>
      Please enter your OpenID:<br>
      {{ form.openid(size=80) }}
      {% for error in form.openid.errors %}
        <span style="color:red;">[{{ error }}]</span>
      {% endfor %}
    </p>
    <p>
      {{ form.remember_me }} Remember Me
    </p>
    <p>
      <input value="Sign in" type="submit">
    </p>
  </form>
{% endblock %}

添加了錯(cuò)誤的提示信息

處理OpenIDs

為了是用戶更容易的登錄網(wǎng)站灌诅,我們添加一些openid的連接,兒不需要用戶手動(dòng)的輸入OpenID
先定義一些OpenID的提供者暴氏,定義在config.py

WTF_CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'

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=""%s",remember_me=%s'%
                (form.openid.data,str(form.remember_me.data)))
        return redirect('/index')
    return render_template('login.html',
                            title="Sign in",
                            form=form,
                            providers=app.config['OPENID_PROVIDERS'])

還需要修改對(duì)應(yīng)的模板視圖(file app/templates/login.html)

{% extends "base.html" %}

{% block content %}

<script type="text/javascript">
  function set_openid(openid,pr){
    u = openid.search('<username>')
    if(u != -1){
      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 class="" action="" name="login" method="post">
    {{form.hidden_tag()}}
    <p>
      Please enter your OpenID:<br>
      {{ form.openid(size=80) }}
      {% for error in form.openid.errors %}
        <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 value="Sign in" type="submit">
    </p>
  </form>
{% endblock %}

運(yùn)行截圖

寫在最后

我們隊(duì)登錄的表單做了很多的改進(jìn)延塑,但是我們還沒有真正的登錄到系統(tǒng)中,真正的登錄我們需要后臺(tái)的數(shù)據(jù)庫的支持

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末答渔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侥涵,更是在濱河造成了極大的恐慌沼撕,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芜飘,死亡現(xiàn)場(chǎng)離奇詭異务豺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嗦明,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門笼沥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事奔浅」菽桑” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵汹桦,是天一觀的道長(zhǎng)鲁驶。 經(jīng)常有香客問我,道長(zhǎng)舞骆,這世上最難降的妖魔是什么钥弯? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮督禽,結(jié)果婚禮上脆霎,老公的妹妹穿的比我還像新娘。我一直安慰自己狈惫,他們只是感情好绪穆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虱岂,像睡著了一般玖院。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上第岖,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天难菌,我揣著相機(jī)與錄音,去河邊找鬼蔑滓。 笑死郊酒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的键袱。 我是一名探鬼主播燎窘,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蹄咖!你這毒婦竟也來了褐健?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤澜汤,失蹤者是張志新(化名)和其女友劉穎蚜迅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俊抵,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谁不,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徽诲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刹帕。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吵血,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偷溺,到底是詐尸還是另有隱情蹋辅,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布亡蓉,位于F島的核電站晕翠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砍濒。R本人自食惡果不足惜淋肾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爸邢。 院中可真熱鬧樊卓,春花似錦、人聲如沸杠河。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽券敌。三九已至唾戚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間待诅,已是汗流浹背叹坦。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卑雁,地道東北人募书。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像测蹲,于是被迫代替她去往敵國(guó)和親莹捡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 22年12月更新:個(gè)人網(wǎng)站關(guān)停扣甲,如果仍舊對(duì)舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,165評(píng)論 22 257
  • 第二部分 Blog例子 第八章 用戶驗(yàn)證 大部分程序需要追蹤用戶身份篮赢。當(dāng)用戶連接到程序,通過一系列步驟使自己的身份...
    易木成華閱讀 1,284評(píng)論 0 4
  • 第四章 Web表單 序:為什么需要Flask-wtf 第 2 章中介紹的請(qǐng)求對(duì)象包含客戶端發(fā)出的所有請(qǐng)求信息文捶。其中...
    科幻經(jīng)典閱讀 840評(píng)論 0 2
  • 親愛的荷逞,下面的話,我們都不做當(dāng)事人粹排,仔細(xì)看!客觀涩澡! 我也發(fā)現(xiàn)顽耳,就算中間她認(rèn)識(shí)到你不理她,也一直跟你主動(dòng)說話。并且后...
    這樣也挺好啦閱讀 217評(píng)論 0 0
  • 昨晚看了魔鏡的五月總結(jié)射富,六月計(jì)劃膝迎,感觸頗深。在她和彩虹身上胰耗,一而再限次,再而三的感嘆:自律里藏著自由! 我無別處好柴灯,就...