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è)字段千埃,StringField
和BooleanField
,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ù)傳入到模板中,我們還引入了
flash
和redirect
,可以暫時(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 %}
寫在最后
我們隊(duì)登錄的表單做了很多的改進(jìn)延塑,但是我們還沒有真正的登錄到系統(tǒng)中,真正的登錄我們需要后臺(tái)的數(shù)據(jù)庫的支持