您好,登錄后才能下訂單哦!
?視圖函數(shù)作用即生成請求的響應(yīng),如果把業(yè)務(wù)邏輯和表現(xiàn)邏輯混在一起會導(dǎo)致代碼難以理解和維護(hù)。吧表現(xiàn)邏輯轉(zhuǎn)移到模板中能夠提升程序的可維護(hù)性。
?模板是一個響應(yīng)文本的文件,其中包含用占位變量表示的動態(tài)部分,其具體值只在請求的上下文才能知道。
?使用真實(shí)值替換變量,在返回最終得到的響應(yīng)字符串,這一過程稱為渲染。
?在默認(rèn)情況下,F(xiàn)lask程序會在templates子文件夾中尋找模板。在下一個hello.py版本中,要把前面定義的模板保存在templates文件夾中,并分別命名為index.html和user.html。
from flask import Flask,render_template
from flask_script import Manager
app = Flask(__name__)
manager = Manager( app )
@app.route('/')
def index():
return render_template('index.html')
@app.route('/user/<name>')
def user(name):
return render_template('user.html',name=name)
if __name__ == "__main__":
manager.run()
?Jinja2能識別所有類型的變量,甚至是一些復(fù)雜的類型,例如列表、字典和對象。在模板中使用變量的一些示例如下:
<p>DICT {{ mydict['key'] }}</p>
<p>LIST {{ mylist[3] }}</p>
<p>list with a variable index: {{ mylist[myintvar]}}</p>
<p> object's method: {{ myobj.somemethod() }} </p>
條件控制語句
{% if user %}
{% else %}
{% endif %}
for循環(huán)語句
{% for comment in comments %}
{% endfor %}
支持宏
{% marco render_comment(comment) %}
多處重復(fù)使用的模板代碼片段可以寫入單獨(dú)的文件,再包含在所有的模板中,以避免重復(fù):
{ % include 'comment.html' %}
<html>
<head>
{% block head %}
<title>
{% block title %}
{% endblock %}
- My Application
</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
{% extends bash.html %}
{% block title %}
Index
{% endblock%}
{% block head%}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h2>hello,world</h2>
{% endblock %}
? Bootstrap是Twitter開發(fā)的一個開源框架,它提供的用戶界面組件可用于創(chuàng)建整潔且具有吸引力的網(wǎng)頁,并且這些網(wǎng)頁還能兼容所有現(xiàn)代的Web瀏覽器。
?Bootstrap是客戶端框架,不會直接涉及服務(wù)器。要下在程序中繼承Bootstrap,顯然需要對模板做所有必要的改動,更簡單的方法就是安裝Flask-Bootstrap的Flask擴(kuò)展,簡化集成的過程。
pip install flask-bootstrap
Flask擴(kuò)展一般在創(chuàng)建程序?qū)嵗龝r初始化。
from flask.ext.bootstrap import Bootstrap
bootstrap = Bootstrap(app)
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Flasky</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
<div class="page-header">
<h2>Hello, {{ name }}!</h2>
</div>
</div>
{% endblock %}
代碼詳解:
Flaks-Bootstrap基模板中定義的塊:
塊名 說明
- doc 整個HTML文檔
- html_attribs <html>標(biāo)簽的屬性
- html <html>標(biāo)簽的內(nèi)容
- head <head>標(biāo)簽中的內(nèi)容
- title <title>標(biāo)簽中的內(nèi)容
- metas 一組<meta>標(biāo)簽
- styles 層疊樣式表定義
- body_attribs <body>標(biāo)簽的屬性
- body <body>標(biāo)簽中的內(nèi)容
- navbar 用戶定義的導(dǎo)航條
- content 用戶定義的頁面內(nèi)容
- scripts 文檔底部的JavaScript聲明
Flask允許程序使用基于模板的自定義錯誤頁面,最常見的錯誤代碼有兩個:
404,客戶端請求未知頁面或路由時顯示。
500,有未處理的異常時顯示。
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'),404
@app.errorhandler(500)
def internal_server_error(e):
return render_templte('500.html'),500
?在模板中直接編寫簡單路由的URL連接不難,但對于包含可變部分的動態(tài)路由,在模板中構(gòu)建正確的URL就很困難;并且直接編寫URL會對代碼中定義的路由產(chǎn)生不必要的依賴。
?Flask提供了url_for()輔助函數(shù),可以使用程序URL映射中保存的信息生成URL。
?url_for()函數(shù)最簡單的用法是以視圖函數(shù)名(后者app.add_url_route()定義路由時使用的端點(diǎn)名)作為參數(shù),返回對應(yīng)的URL。
?使用url_for()生成動態(tài)地址時,將動態(tài)部分作為關(guān)鍵字參數(shù)傳入。例如,url_for('user',name='john',_external=True)的返回結(jié)果是http://localhost:5000/user/john
?傳入url_for()的關(guān)鍵字參數(shù)不僅限于動態(tài)路由中的參數(shù)。函數(shù)能將任何額外參數(shù)添加到查詢字符串中。例如,url_for('index',page=2)的返回結(jié)果是/?page=2
?默認(rèn)設(shè)置下,F(xiàn)lask在程序根目錄中名為static的子目錄中尋找靜態(tài)文件。如果需要,可在static文件夾中使用子文件夾存放文件。
?問題背景:如果Web程序的用戶來自世界各地,那么處理日期和時間就不是一個簡單的任務(wù)。
?解決方法:通過使用JavaScript開發(fā)的優(yōu)秀客戶端開源代碼庫,名為moment.js,可以在瀏覽器中渲染日期和時間。Flask-Monment是一個Flask程序擴(kuò)展。能把moment.js集成到Jinja2模板中。
Flask-Moment可以通過pip安裝:
pip install flask-moment
from flask.ext.moment import Moment
moment = Moment(app)
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblcok %}
from datetime improt datetime
@app.route('/')
def index():
return render_template('index.html',current_time=datetime.utcnow())
<p>The local date and time is {{ moment(current_time).format('LLL) }}</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
更多moment.js用法:http://momentjs.com/docs/#/displaying/
Flask-Moment假定服務(wù)器端程序處理的時間是“純正的”datetime對象,且使用UTC表示。
?對于一些重復(fù)操作(生成表單的HTML代碼和驗(yàn)證提交的表單數(shù)據(jù)),F(xiàn)lask-WTF擴(kuò)展可以把處理Web表單的過程變成一種愉悅的體驗(yàn)。這個擴(kuò)展對獨(dú)立的WTForms包進(jìn)行了包裝,方便集成到Flask程序中。
WTForms官網(wǎng):http://wtforms.simplecodes.com
pip install flaks-wtf
?默認(rèn)情況,F(xiàn)lask-WTF能保護(hù)所有表單面授跨站請求偽造(CSRF)的***。為了實(shí)現(xiàn)CSRF保護(hù),F(xiàn)lask-WTF需要程序設(shè)置一個密鑰。Flask-WTF使用這個密鑰生成加密令牌,再用令牌驗(yàn)證請求中表單數(shù)據(jù)的真?zhèn)巍?/p>
示例代碼(設(shè)置Flask-WTF):
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
使用Flask-WTF時,每個Web表單都由一個繼承自Form的類表示。
示例代碼(一個簡單的Web表單,包含一個文本字段和一個提交按鈕):
from flaks.ext.wtf import Form
from wtforms import StringField,SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField("What's your name?",validators=[Required()])
submit = SubmitField('Submit')
WTForms支持的HTML標(biāo)準(zhǔn)字段
- StringField 文本字段
- TextAreaField 多行文本字段
- PasswordField 密碼文本字段
- HiddenField 隱藏文本字段
- DateField 文本字段,值為 datetime.date 格式
- DateTimeField 文本字段,值為 datetime.datetime 格式
- IntegerField 文本字段,值為整數(shù)
- DecimalField 文本字段,值為 decimal.Decimal
- FloatField 文本字段,值為浮點(diǎn)數(shù)
- BooleanField 復(fù)選框,值為 True 和 False
- RadioField 一組單選框
- SelectField 下拉列表
- SelectMultipleField 下拉列表,可選擇多個值
- FileField 文件上傳字段
- SubmitField 表單提交按鈕
- FormField 把表單作為字段嵌入另一個表單
- FieldList 一組指定類型的字段
WTForms驗(yàn)證函數(shù)
- Email 驗(yàn)證電子郵件地址
- EqualTo 比較兩個字段的值;常用于要求輸入兩次密碼進(jìn)行確認(rèn)的情況
- IPAddress 驗(yàn)證 IPv4 網(wǎng)絡(luò)地址
- Length 驗(yàn)證輸入字符串的長度
- NumberRange 驗(yàn)證輸入的值在數(shù)字范圍內(nèi)
- Optional 無輸入值時跳過其他驗(yàn)證函數(shù)
- Required 確保字段中有數(shù)據(jù)
- Regexp 使用正則表達(dá)式驗(yàn)證輸入值
- URL 驗(yàn)證 URL
- AnyOf 確保輸入值在可選值列表中
- NoneOf 確保輸入值不在可選值列表中
示例代碼:(使用Flask-WTF和Flask-Bootstrap渲染表單)
{% extends 'base.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h2>hello,{% if name %}{{ name }}{% else %}Stranger{% endif%}</h2>
</div>
{{ wtf.quick_form(form)}}
{% endblock %}
示例代碼:(視圖函數(shù)index()不僅要渲染表單,還要接受表單中的數(shù)據(jù)。)
@app.route('/',methods=['GET','POST'])
def index():
name = None
form = NameForm()
if form.validate_on_submit():
name = form.name.data
form.name.data = ''
return render_template('index.html',form=form,name=name)
?問題背景:當(dāng)用戶輸入名字后提交表單,再點(diǎn)擊瀏覽器的刷新按鈕,會看到一個警告,關(guān)于要求再次提交表單之前進(jìn)行確認(rèn)。之所以會出這種問題,是因?yàn)樗⑿马撁鏁r瀏覽器會重新發(fā)送之前已經(jīng)發(fā)送過的最后一個請求。
?解決方案:使用重定向作為POST請求的響應(yīng),而不是使用常規(guī)響應(yīng)。重定向是一種特殊的響應(yīng),響應(yīng)內(nèi)容是URL,而不是包含HTML代碼的字符串。瀏覽器收到這種響應(yīng),會向重定向的URL發(fā)起GET請求,顯示頁面的內(nèi)容。
?另一問題:如果使用上面的解決方案,程序在處理POST請求時,使用from.name.data獲取用戶輸入的名字,一旦請求結(jié)束,數(shù)據(jù)也就丟失了。所以需要程序?qū)?shù)據(jù)存儲到用戶會話中,在請求之間“記住”數(shù)據(jù)。用戶是一種私有存儲,存在每個連接到服務(wù)器的客戶端中。
示例代碼:
from flask import Flask,render_template,session,redirect,url_for
@app.route('/',methods=['GET','POST'])
def index():
form = NameForm()
if form.validate_on_submit():
session['name'] = form.name.data
return redirect(url_for('index'))
return render_template('index.html',form=form,name=session.get('name')))
?問題背景:用戶提交了有一項(xiàng)錯誤的登錄表單,服務(wù)器發(fā)回的響應(yīng)重新渲染了登錄表單,并在表單上面顯示信息,提示用戶名或密碼錯誤。
示例代碼:
from flask ipmort Flask,render_template,session,redirect,url_for,flash
@app.route('/',methods=['GET','POST'])
def index():
form = NameForm()
if form.validate_on_submit():
old_name = session.get('name')
if old_name is not None and old_name != form.name.data:
flash("Looks like you have changed your name")
session['name'] = olde_name
return redirect(url_for('index'))
return render_template('index.html',name=session.get('name'),form=form) ```
* ?代碼詳解:代碼會將每一次提交的名字與上一次**存儲在會話中的名字**進(jìn)行比較,如果兩者不一樣則會發(fā)給客戶端下一個響應(yīng)中顯示一個信息。
* ?僅調(diào)用flash()函數(shù)并不能把消息顯示出來,程序使用的模板要渲染這些信息,最好在基礎(chǔ)模板中渲染Flash消息,因?yàn)檫@樣所有頁面都能使用這些消息。Flask把**get_flashed_messages()函數(shù)**開放給模板,用來獲取并渲染消息。
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">
×
</button>
{{ message }}
</div>
{% endfor %}
{% block page_content %}
{% endblock %}
</div>
{% endblock %}
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。