這個(gè)系列是學(xué)習(xí)《Flask Web開發(fā):基于Python的Web應(yīng)用開發(fā)實(shí)戰(zhàn)》的部分筆記
雖然可以在視圖中直接編寫 HTTP 頁面的內(nèi)容,但是這種方式很原始。將與數(shù)據(jù)庫交互的業(yè)務(wù)邏輯,與生成響應(yīng)的表現(xiàn)邏輯混在了一起。一方面不適合大型、復(fù)雜頁面的編寫、維護(hù),結(jié)構(gòu)不清晰,另外,由于業(yè)務(wù)邏輯通常由程序員完成,而表現(xiàn)邏輯由設(shè)計(jì)師完成,這樣雙方的工作會(huì)互相影響。
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
flask 支持 MVC 模型,由程序員在視圖中完成與數(shù)據(jù)庫的交互——業(yè)務(wù)邏輯(M),而顯示給客戶端的頁面在模板中定義(V),由設(shè)計(jì)師完成。
模板是一個(gè)包含響應(yīng)文本的文件(通常是 HTML),其中包含用 占位變量 表示的動(dòng)態(tài)部分, 具體值只在收到具體的請求后,通過上下文才能知道,模板中最主要的是前端技術(shù),HTLM、CSS、JS 等。
模板引擎實(shí)現(xiàn)對模板的渲染,就是根據(jù)上下文,對模板中的占位變量,用真實(shí)值替換,形成最終的響應(yīng)文件。
模板文件夾
默認(rèn)情況下,Flask 在程序文件夾中的 templates 子文件夾中尋找模板。
模板的調(diào)用
flask 使用 jinjia2 模板引擎,為了便于使用,已經(jīng)集成到 render_template 函數(shù)中,可以直接調(diào)用。
from flask import Flask, render_template
@app.route('/')
def index():
return render_template('index.html') # 注意,是包含 .html 后綴的完整文件名
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
第一個(gè)參數(shù)是模板的名稱,然后是 鍵/值 對,name=name左邊表示模板中的占位符,右邊是當(dāng)前視圖中的變量。意思是,將當(dāng)前視圖中變量name的值,賦值給模板中名為name的占位符,用于渲染。
變量
- 表示
{{ name }}
占位符,告訴模板引擎,這個(gè)位置的值從渲染模板時(shí)傳遞的數(shù)據(jù)字典中獲取
- 支持的變量類型
支持所有類型,字符串、整型、列表、字典 ......
- 修改顯示樣式
通過使用過濾器,可以定制 變量的值 顯示的效果,比如 大小寫。{{ name | 過濾器 }}
- 模板變量
在模板中設(shè)置模板變量
{% set name = 'john' %}
控制結(jié)構(gòu)
主要用于改變渲染流程
- 條件控制
if...else...endif
判斷條件是否符合,并執(zhí)行相應(yīng)的語句
- 循環(huán):for...endfor
用于渲染一組元素
- 宏:macro...endmacro
類似函數(shù)
定義一個(gè)宏,指定宏的名稱、參數(shù),調(diào)用
{% macro x(y) %}
...
{% endmacro %}
{{ x(y) }}
如果需要在多個(gè)模板中復(fù)用,可以將宏的定義放入一個(gè)文件,‘macro.html’
{% macro x(y) %}
...
{% endmacro %}
然后導(dǎo)入使用
import 'macro.html' as macro
{{ macro.x(y) }}
- 繼承:
如果多個(gè)頁面的大部分內(nèi)容相同,可以定義一個(gè)母模板,包含相同的內(nèi)容,然后子模板繼承內(nèi)容,并根據(jù)需要進(jìn)行部分修改
base.html,母模板,其中,用{% block title %}...{% endblock %}定義了可以由子模板替換的區(qū)域,title是區(qū)塊的名稱,可以有多個(gè)區(qū)塊
{% block title %}Hello{% endblock %}
在子模板中,聲明繼承的母模板,然后用{% block title %}...{% endblock %}指定替換哪個(gè)區(qū)塊的內(nèi)容,并填入自己的內(nèi)容。子模板中沒有指定的區(qū)塊,默認(rèn)使用母模板的內(nèi)容
{% extends "base.html" %}
{% block title %}john{% endblock %}
如果希望能夠保留母版的內(nèi)容,并添加新內(nèi)容,可以使用super()
{% extends "base.html" %}
{% block title %}
{{ super() }}
john
{% endblock %}
模板里面,不能同時(shí)有兩個(gè)
{% extends " " %}語句,即使另一個(gè)被注釋了也不行
- 包含:
如果多個(gè)網(wǎng)頁中都有一段內(nèi)容相同,可以將相同的內(nèi)容放入一個(gè)文件中comments.html,通過include導(dǎo)入
{% include 'comments.html' %}
bootstrap
Bootstrap是 Twitter 開發(fā)的一個(gè)開源框架,它提供的用戶界面組件可用于創(chuàng)建整潔且具有吸引力的網(wǎng)頁,而且這些網(wǎng)頁還能兼容所有現(xiàn)代 Web 瀏覽器。
一個(gè)名為Flask-Bootstrap的 Flask 擴(kuò)展, 可以簡化在程序中集成 Bootstrap 的過程。
安裝:
$ pip install flask-bootstrap
初始化
從 flask.ext 命名空間中導(dǎo)入,然后把 程序?qū)嵗齻魅霕?gòu)造方法進(jìn)行初始化。
run.py
from flask.ext.bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之后,就可以在程序中使用一個(gè)包含所有 Bootstrap 文件的基模板。 這個(gè)模板利用 Jinja2 的模板繼承機(jī)制,讓程序擴(kuò)展一個(gè)具有基本頁面結(jié)構(gòu)的基模板,其中 就有用來引入 Bootstrap 的元素。
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
{% endblock %}
{% block content %} <div class="container">
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
Jinja2 中 的 extends 指 令 從 Flask-Bootstrap 目錄中導(dǎo)入 bootstrap/base.html, 從而實(shí)現(xiàn)模板繼承。Flask-Bootstrap 中的基模板提供了一個(gè)網(wǎng)頁框架,引入了 Bootstrap 中的所有 CSS 和 JavaScript 文件。
virtualenv 環(huán)境中,目錄為
lib/python2.7/site-packages/flask_bootstrap/templates/bootstrap/
基模板中定義了可在衍生模板中重定義的塊。block 和 endblock 指令定義的塊中的內(nèi)容可添加到基模板中。
Bootstrap 官方文檔是很好的學(xué)習(xí)資源,有很多可以直接復(fù)制粘貼的示例。
自定義錯(cuò)誤頁面
像常規(guī)路由一樣,Flask 允許程序使用基于模板的自定義錯(cuò)誤頁面。最常見的錯(cuò)誤代碼有兩個(gè):404,客戶端請求未知頁面或路由時(shí)顯示;500,有未處理的異常時(shí)顯示。
自定義錯(cuò)誤頁面
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
和視圖函數(shù)一樣,錯(cuò)誤處理程序也會(huì)返回響應(yīng)。它們還返回與該錯(cuò)誤對應(yīng)的數(shù)字狀態(tài)碼。 返回指定的數(shù)字狀態(tài)碼似乎沒有什么用 ?
url_for 生成連接
模板中可能有去往多個(gè)不同頁面的鏈接,例如導(dǎo)航條。
在模板中直接編寫簡單路由的 URL 鏈接不難,但對于包含可變部分的動(dòng)態(tài)路由,在模板中構(gòu)建正確的 URL 就很困難。而且,直接編寫 URL 會(huì)對代碼中定義的路由產(chǎn)生不必要的 依賴關(guān)系(hardcode)。如果修改 路由、視圖 的綁定關(guān)系, 模板中的鏈接可能會(huì)失效。
為了避免這些問題,Flask 提供了url_for()輔助函數(shù),它可以使用程序URL映射中保存的信息,根據(jù)視圖名稱生成 URL。
例如,對于下面的視圖
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
調(diào)用 url_ for('index')得到的結(jié)果是/。調(diào)用url_for('index', _external=True)返回的則是絕對地址,是http://localhost:5000/。
在程序內(nèi)(模板、視圖中)生成連接程序內(nèi)不同路由的鏈接時(shí),使用
相對地址就足夠了,瀏覽器、程序能夠根據(jù)當(dāng)前的 URL 補(bǔ)全。但如果要在瀏覽器以外生成鏈接,例如在確認(rèn)郵件中的鏈接,則必須使用絕對地址,否則誰也不知道前綴是什么。
使用url_for()生成鏈接時(shí),將動(dòng)態(tài)部分作為關(guān)鍵字參數(shù)傳入。例如,
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
url_for ('user', name='john', _external=True) 的返回結(jié)果是 http://localhost:5000/user/john。
默認(rèn) _external 為 False,表示生成相對路徑;為 True 時(shí),表示生成絕對路徑
函數(shù)能將任何額外參數(shù)添加到查詢字符串中。例如,
url_for('user', name='john', page=2)的返回結(jié)果是/user/john/?page=2
對于多層的模板結(jié)構(gòu),render_template 函數(shù)中需要添加從templates目錄下文件夾開始的路徑信息,render_template('main/index.html'),結(jié)構(gòu)為templates/main/index.html,url_for() 需要用.隔開目錄,url_for('main.index.html')。