第三章 模板
序
為什么要分離
易于維護(hù)的代碼,關(guān)鍵在于保持簡(jiǎn)單的結(jié)構(gòu)。
而我們之前編寫的hello.py雖然簡(jiǎn)單,卻混合了兩種不同的部分:
如何生成頁(yè)面數(shù)據(jù)霍狰、如何顯示。
將這兩部分混合在一起會(huì)帶來(lái)復(fù)雜性饰及。
注意hello.py中的return '<h1>Hello, world</h1>'
蔗坯。
第一部分是生成數(shù)據(jù):生成Hello,world,第二部分是如何顯示:<h1>
一級(jí)標(biāo)題燎含。
為什么需要模板
分離后我們將把hello,world宾濒!這樣的html頁(yè)面單獨(dú)存放。
這樣當(dāng)用戶打開一個(gè)網(wǎng)址時(shí)屏箍,服務(wù)器立即把對(duì)應(yīng)的html頁(yè)面發(fā)送給他绘梦。
可事情這么簡(jiǎn)單就好了,很多html頁(yè)面中的東西并不是一成不變的赴魁。
我們需要一種技術(shù)卸奉,讓頁(yè)面中的一部分可以動(dòng)態(tài)變化:渲染。
為了渲染模板颖御,F(xiàn)lask使用了Jinja2.
3.1 Jinja2模板引擎
序
一個(gè)簡(jiǎn)單的靜態(tài)模板:templates/index.html
<h1>Hello world!</h1>
增加動(dòng)態(tài)部分的形式 :templates/user.html
<h1>Hello ,{{ name }}!</h1>
第一個(gè)模板為靜態(tài)榄棵,不需要Jinja2也能支持。
而Jinja2會(huì)對(duì)動(dòng)態(tài)的部分進(jìn)行替換,如第二個(gè)模板中的動(dòng)態(tài)部分疹鳄。
此時(shí)用html直接解析會(huì)出現(xiàn)錯(cuò)誤拧略,必須有類似Jinja2的模板引擎。
為了簡(jiǎn)化程序尚辑,不需要在Flask程序里顯示調(diào)用Jinja2。
3.1.1 渲染模板
如何使用模板
在Flask程序里調(diào)用render_template函數(shù)后盔腔,就使用了模板杠茬。
示例 3-3 hello.py: 渲染模板
from flask import Flask, render_template
# ...
@app.route('/')
def index():
return render_template('index.html')
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
模板參數(shù)和搜索路徑
在例3-3中,render_template有兩個(gè)參數(shù)弛随。
第一個(gè)是模板文件名瓢喉,以html結(jié)尾,默認(rèn)在程序/templates
文件夾下搜尋舀透。
還記得剛開始我們講Flask類的參數(shù)(__name__)
的作用嗎栓票。
第二個(gè)是動(dòng)態(tài)參數(shù)的值,如name=name:
前一個(gè)name就是模板中的{{ name }}(見(jiàn)序的第二個(gè)文件)愕够,即模板中的動(dòng)態(tài)部分走贪;
后一個(gè)name是動(dòng)態(tài)部分要在頁(yè)面顯示的值,在這里是函數(shù)user的參數(shù)惑芭,它會(huì)被傳給模板渲染坠狡。
3.1.2 變量
什么是變量
模板中使用的兩個(gè)大括號(hào)包裹的{{ name }}表示一個(gè)變量,
它的值由Flask程序提供(渲染)遂跟。
Jinja2能識(shí)別python中所有類型的變量逃沿,例如列表、字典和對(duì)象幻锁。
一些在模板中使用變量的示例:
<p>引用字典的一個(gè)值: {{ mydict['key'] }}.</p>
# <p>是html標(biāo)簽凯亮,表示段落(paragraph)
<p>引用列表的一個(gè)值: {{ mylist[3] }}.</p>
<p>引用列表中的一個(gè)值,鍵為變量: {{ mylist[myintvar] }}.</p>
<p>引用對(duì)象的一個(gè)方法: {{ myobj.somemethod() }}.</p>
什么是過(guò)濾器
有時(shí)候出于安全考慮或?qū)ψ兞窟M(jìn)行形式變更哄尔,
這時(shí)候需要用到過(guò)濾器假消。
例如以首字母大寫形式顯示變量 name 的值:
Hello, {{ name|capitalize }}
使用過(guò)濾器,在變量名后加豎線和過(guò)濾器名即可岭接。
常見(jiàn)的過(guò)濾器
capitalize # 把值的首字母轉(zhuǎn)換成大寫置谦,其他字母轉(zhuǎn)換成小寫
safe # 渲染值時(shí)不轉(zhuǎn)義
lower # 把值轉(zhuǎn)換成小寫形式
upper # 把值轉(zhuǎn)換成大寫形式
title # 把值中每個(gè)單詞的首字母都轉(zhuǎn)換成大寫
trim # 把值的首尾空格去掉
striptags # 渲染之前把值中所有的 HTML 標(biāo)簽都刪掉
特別的safe過(guò)濾器
默認(rèn)情況下,出于安全考慮亿傅, Jinja2 會(huì)轉(zhuǎn)義所有變量媒峡。
例如,如果一個(gè)變量的值為 '<h1>Hello</h1>'
葵擎,
Jinja2 會(huì)將其渲染成 '<h1>Hello</ h1>'
谅阿,
瀏覽器能顯示這個(gè) h1 元素,但不會(huì)進(jìn)行解釋。
很多情況下需要顯示變量中存儲(chǔ)的 HTML 代碼签餐,
這時(shí)就可使用 safe 過(guò)濾器寓涨。
千萬(wàn)別在不可信的值上使用 safe 過(guò)濾器,
例如用戶在表單中輸入的文本氯檐。
完整的過(guò)濾器列表可在
Jinja2 文檔查看戒良。
3.1.3 控制結(jié)構(gòu)
if條件控制
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
控制語(yǔ)句以{% 關(guān)鍵字%}開始,
注意有一個(gè)結(jié)束語(yǔ)句endif冠摄。
for循環(huán)
一個(gè)常見(jiàn)需求是在模板中渲染一組元素糯崎。
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
同樣有endfor,Jinja2中的結(jié)束關(guān)鍵字是end+開始關(guān)鍵字河泳,中間沒(méi)有空格沃呢。
<li>
用來(lái)定義列表的條目,可以用在無(wú)序列表<ul>
和有序列表<ol>
中。
宏
宏類似于函數(shù)拆挥,例如:
{% macro render(w) %}
<li>{{ w }}</li>
{% endmacro %}
<ul>
{% for w in word %}
{{ render(w) }}
{% endfor %}
</ul>
第二段for循環(huán)里的render就是前面定義的宏薄霜,
作用是對(duì)序列word中的每一項(xiàng)進(jìn)行渲染。
為了重復(fù)使用宏纸兔,我們可以將其保存在單獨(dú)的文件中惰瓜,
然后在需要使用的模板中導(dǎo)入。
例如我們把若干宏保存到macros.html后汉矿,可以用類似python包的形式導(dǎo)入鸵熟。
{% import 'macros.html' as macros %}
<ul>
{% for w in word %}
{{ macros.render(w) }}
{% endfor %}
</ul>
模板繼承
一種方式是使用include:模板插入。
需要在多處重復(fù)使用的模板代碼片段可以寫入單獨(dú)的文件负甸,
再包含在模板的某一位置中流强,以避免重復(fù):
{% include 'common.html' %}
另一種是使用extends:模板繼承。
它類似于 Python 代碼中的類繼承呻待,具有更強(qiáng)的功能打月。
首先,創(chuàng)建一個(gè)名為 base.html 的基模板:
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
使用base.html的模板叫子模板蚕捉,base是它的父模板奏篙。子模板可以修改block元素。
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
extends 聲明子模板繼承自base.html迫淹,
extends必須放在第一行秘通。
子模板重新定義了base.html中的2個(gè)block,
在子模板的block中敛熬,如果想包含在父模板block的內(nèi)容肺稀,
使用{{ super() }},
這會(huì)獲取對(duì)應(yīng)block的內(nèi)容应民。
這種方式和include的不同在于话原,include寫好的片段不再修改夕吻,只是簡(jiǎn)單插入,
最終由調(diào)用include的模板進(jìn)行渲染繁仁。
而extends繼承涉馅,是在base.html上做擴(kuò)展修改,
最終由extends所在的模板進(jìn)行渲染黄虱。
3.2 Flask-Bootstrap
Bootstrap是什么
Bootstrap是Twitter開發(fā)的一個(gè)開源框架稚矿,
可用來(lái)快速開發(fā)美觀的網(wǎng)頁(yè)外觀。
它不但兼容所有的現(xiàn)代web瀏覽器捻浦,
而且一份代碼晤揣,便可以支持手機(jī)、電腦默勾、平板的瀏覽碉渡。
Bootstrap是客戶端框架聚谁,因此不會(huì)直接涉及服務(wù)器母剥。
服務(wù)器需要的只是提供使用了Bootstrap和JavaScript的代碼,
并且在這些代碼中實(shí)例化所需組件形导。
這些操作最理想的執(zhí)行場(chǎng)所就是模板环疼。
為什么需要Flask-Bootstrap
要想在程序中使用Bootstrap,
顯然原來(lái)的模板要進(jìn)行必要的改動(dòng)來(lái)適應(yīng)它朵耕。
不過(guò)有人已經(jīng)開發(fā)了Flask-Bootstrap炫隶,
用來(lái)簡(jiǎn)化這些改動(dòng)。
如何安裝使用Flask-Bootstrap
Flask-Bootstrap使用pip安裝:
(venv) $ pip install flask-bootstrap
類似Flask-Script阎曹,F(xiàn)lask擴(kuò)展一般都在創(chuàng)建程序?qū)嵗龝r(shí)初始化伪阶。
下面是Flask-Bootstrap的初始化方法。
from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之后处嫌,
就可以在程序中使用一個(gè)包含所有 Bootstrap 文件的基模板栅贴。
這個(gè)模板利用 Jinja2 的模板繼承機(jī)制,
讓程序擴(kuò)展一個(gè)具有基本頁(yè)面結(jié)構(gòu)的基模板熏迹,
其中就有用來(lái)引入 Bootstrap 的元素檐薯。
使用Flask-Bootstrap的模板
{% 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">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
它和Flask-Script一樣,初始化了Flask的實(shí)例app注暗,
但不同的是坛缕,Bootstrap實(shí)例沒(méi)有run方法,
還是像以前一樣運(yùn)行app.run()捆昏。
對(duì)這個(gè)模板的簡(jiǎn)單說(shuō)明
現(xiàn)在你看到的模板比較復(fù)雜赚楚,我們現(xiàn)在只需要知道,
整個(gè)模板定義了3個(gè)塊骗卜,title直晨,navbar和content搀军。
title很明顯是網(wǎng)頁(yè)標(biāo)簽bar上出現(xiàn)的網(wǎng)站信息,
navbar就是導(dǎo)航條勇皇,而content就是網(wǎng)頁(yè)的主體部分罩句。
其中的Flasky,Home敛摘,Hello门烂,你也可以自己替換成中文。
注意extends后面兄淫,在當(dāng)前程序下并沒(méi)有這個(gè)bootstrap目錄屯远,
也就是說(shuō),我們寫的bootstrap實(shí)際上是表明了我們引用了
bootstrap的模板捕虽,模板名叫base.html慨丐,
具體路徑是C:\Python34\Lib\site-packages\flask_bootstrap\templates\bootstrap,
根據(jù)你的python版本不同泄私,路徑中的python34可能是python27或python36等等房揭。
你可以到這個(gè)路徑下看看還有什么模板。
Flask-Bootstrap基模板中定義的塊
塊名 | 說(shuō)明 |
---|---|
doc | 整個(gè)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 | 用戶定義的頁(yè)面內(nèi)容 |
scripts | 文檔底部的JavaScript聲明 |
表 3-2 中的很多塊都是 Flask-Bootstrap 自用的晌端,
如果直接重定義可能會(huì)導(dǎo)致一些問(wèn)題捅暴。
例如,Bootstrap 所需的文件在 styles 和 scripts 塊中聲明咧纠。
如果程序需要向已經(jīng)有內(nèi)容的塊中添加新內(nèi)容蓬痒,
必須使用 Jinja2 提供的 super() 函數(shù)。
例如漆羔,如果要在衍生模板中添加新
的 JavaScript 文件梧奢,需要這么定義 scripts 塊:
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}
3.3 自定義錯(cuò)誤頁(yè)面
為什么需要自定義錯(cuò)誤頁(yè)面
現(xiàn)在你在地址欄輸入一個(gè)不存在的地址,
出來(lái)的404頁(yè)面會(huì)顯示很多英文演痒,
并且與使用了Bootstrap的頁(yè)面不一致亲轨,
這或許不是你想要的。
有哪些錯(cuò)誤頁(yè)面
Flask允許程序使用基于模板的自定義錯(cuò)誤頁(yè)面嫡霞。
最常見(jiàn)的錯(cuò)誤代碼有兩個(gè):
- 404瓶埋, 客戶端請(qǐng)求未知頁(yè)面或路由時(shí)顯示;
- 500诊沪,有未處理的異常時(shí)顯示养筒。
自定義錯(cuò)誤的示例
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
裝飾器后出現(xiàn)了新的方法:errorhandler。
此方法指定了它想改變的錯(cuò)誤頁(yè)面端姚。
函數(shù)接受了一個(gè)e的錯(cuò)誤晕粪,
這個(gè)值在這并沒(méi)有被使用。
注意返回渲染的模板后渐裸,還加上了錯(cuò)誤代碼巫湘。
我們稍后可以試試不加會(huì)怎樣装悲。
布局一致的要求
我們?cè)谏侠懈嬖VFlask去尋找404.html和500.html這兩個(gè)模板,
而現(xiàn)在templates目錄下沒(méi)有這兩個(gè)模板尚氛,
也不符合extends bootstrap的情況诀诊,
如果你無(wú)法忍受默認(rèn)的錯(cuò)誤頁(yè)面,
那這兩個(gè)模板必須我們自己編寫阅嘶。
這些模板應(yīng)該和常規(guī)頁(yè)面使用相同的布局属瓣,
因此要有一個(gè)導(dǎo)航條和顯示錯(cuò)誤消息的頁(yè)面頭部。
編寫錯(cuò)誤頁(yè)面的笨方法
編寫這些模板最直觀的方法是復(fù)制 templates/user.html讯柔,
分別創(chuàng)建 templates/404.html 和
templates/500.html抡蛙,
然后把這兩個(gè)文件中的頁(yè)面頭部元素改為相應(yīng)的錯(cuò)誤消息。
但這種方法會(huì)帶來(lái)很多重復(fù)勞動(dòng)魂迄。
更靈活的方式
Jinja2 的模板繼承機(jī)制可以幫助我們解決這一問(wèn)題粗截。
Flask-Bootstrap 提供了一個(gè)具有頁(yè)面基本布局的基模板,
同樣捣炬,程序可以定義一個(gè)具有更完整頁(yè)面布局的基模板熊昌,
其中包含導(dǎo)航條,
而頁(yè)面內(nèi)容則可留到衍生模板中定義遥金。
這個(gè)模板本身也可作為其他模板的基模板浴捆,
例如 templates/user.html蒜田、 templates/404.html 和 templates/500.html稿械。
修改后的基模板
{% 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">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
這個(gè)模板的 content 塊中只有一個(gè) <div> 容器,
其中包含了一個(gè)名為 page_content 的新的空塊冲粤,
塊中的內(nèi)容由衍生模板定義美莫。
如何編寫子模板
現(xiàn)在,程序使用的模板繼承自這個(gè)模板梯捕,
而不直接繼承自 Flask-Bootstrap 的基模板厢呵。
通過(guò)繼承 templates/base.html 模板編寫自定義的 404 錯(cuò)誤頁(yè)面很簡(jiǎn)單,
{% extends "base.html" %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
</div>
{% endblock %}
注意基模板定義的title塊我們也可以重新修改傀顾,
也就是盡量利用父模板的代碼襟铭,
但可以進(jìn)行必要的修改。
現(xiàn)在你可以試試修改index短曾、500和user模板寒砖。
3.4 鏈接輔助函數(shù)
為什么需要鏈接輔助
任何具有多個(gè)路由的程序都需要可以連接不同頁(yè)面的鏈接,例如導(dǎo)航條嫉拐。
在模板中直接編寫簡(jiǎn)單路由的 URL 鏈接不難哩都,
但寫死的URL不具有靈活性,
如果其中有可變部分婉徘,
重新定義路由后漠嵌,模板中的鏈接可能會(huì)失效咐汞。
url_for()的簡(jiǎn)單用法
為了避免這些問(wèn)題, Flask 提供了 url_for() 輔助函數(shù)儒鹿,
它使用 URL 映射中的信息生成 URL化撕。
url_for() 函數(shù)最簡(jiǎn)單的用法是以視圖函數(shù)名作為參數(shù),
返回對(duì)應(yīng)的 URL约炎。
例如侯谁,在當(dāng)前版本的 hello.py 程序中調(diào)用 url_for('index') 得到的結(jié)果是 /。
調(diào)用 url_for('index', _external=True) 返回的則是絕對(duì)地址章钾,
在這個(gè)示例中是 http://localhost:5000/墙贱。
生成連接程序內(nèi)不同路由的鏈接時(shí),使用相對(duì)地址就足夠了贱傀。
如果要生成在瀏覽器之外使用的鏈接惨撇,
則必須使用絕對(duì)地址,
例如在電子郵件中發(fā)送的鏈接府寒。
url_for的更多用法
使用 url_for() 生成動(dòng)態(tài)地址時(shí)魁衙,將動(dòng)態(tài)部分作為關(guān)鍵字參數(shù)傳入。
例如株搔, url_for('user', name='john', _external=True) 的返回結(jié)果是 http://localhost:5000/user/john剖淀。
傳入 url_for() 的關(guān)鍵字參數(shù)不僅限于動(dòng)態(tài)路由中的參數(shù)。
函數(shù)能將任何額外參數(shù)添加到查詢字符串中纤房。
例如纵隔, url_for('index', page=2) 的返回結(jié)果是 /?page=2。
在hello.py的最后注釋掉if __name__
和app.run
兩行炮姨。
添加以下2行代碼并運(yùn)行:
with app.test_request_context():
print(url_for('index'))
test_request_context是Flask實(shí)例的一個(gè)屬性捌刮,
用于在沒(méi)有運(yùn)行Flask實(shí)例時(shí)的上下文測(cè)試,
因?yàn)橐坏゛pp.run()運(yùn)行實(shí)例舒岸,那個(gè)print語(yǔ)句就不會(huì)起作用绅作。
3.5 靜態(tài)文件
什么是靜態(tài)文件
Web 程序不是僅由 Python 代碼和模板組成。
大多數(shù)程序還會(huì)使用靜態(tài)文件蛾派,
例如 HTML代碼中引用的圖片俄认、 JavaScript 源碼文件和 CSS。
靜態(tài)路由
你可能還記得在第 2 章中檢查 hello.py 程序的 URL 映射時(shí)洪乍,
其中有一個(gè) static 路由眯杏。
這是因?yàn)閷?duì)靜態(tài)文件的引用被當(dāng)成一個(gè)特殊的路由,
即 /static/<filename>典尾。
例如役拴, 調(diào)用url_for('static', filename='css/styles.css', _external=True)
得 到 的 結(jié) 果 是 http://localhost:5000/static/css/styles.css。
默認(rèn)設(shè)置下钾埂, Flask 在程序根目錄中名為 static 的子目錄中尋找靜態(tài)文件河闰。
如果需要科平,可在static 文件夾中使用子文件夾存放文件。
服務(wù)器收到前面那個(gè) URL 后姜性,
會(huì)生成一個(gè)響應(yīng)瞪慧,
包含文件系統(tǒng)中 static/css/styles.css 文件的內(nèi)容。
注意filename文件名是完整路徑
定義收藏夾圖標(biāo)的示例
{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename = 'favicon.ico') }}"type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename = 'favicon.ico') }}"type="image/x-icon">
{% endblock %}
圖標(biāo)的聲明會(huì)插入 block head
的末尾部念。
注意如何使用 super() 保留基模板中定義的塊的原始內(nèi)容弃酌。
3.6 Flask-Moment:本地化時(shí)間
為什么要本地化時(shí)間
如果 Web 程序的用戶來(lái)自世界各地,
那么處理日期和時(shí)間可不是一個(gè)簡(jiǎn)單的任務(wù)儡炼。
服務(wù)器需要統(tǒng)一時(shí)間單位妓湘,
這和用戶所在的地理位置無(wú)關(guān),
所以一般使用協(xié)調(diào)世界時(shí)( Coordinated Universal Time乌询, UTC)榜贴。
不過(guò)用戶看到 UTC 格式的時(shí)間會(huì)感到困惑,
他們更希望看到當(dāng)?shù)貢r(shí)間妹田,
而且采用當(dāng)?shù)貞T用的格式唬党。
如何本地化時(shí)間
要想在服務(wù)器上只使用 UTC 時(shí)間,
一個(gè)優(yōu)雅的解決方案是鬼佣,
把時(shí)間單位發(fā)送給 Web 瀏覽器驶拱,
轉(zhuǎn)換成當(dāng)?shù)貢r(shí)間, 然后渲染晶衷。
Web 瀏覽器可以更好地完成這一任務(wù)蓝纲,
因?yàn)樗塬@取用戶電腦中的時(shí)區(qū)和區(qū)域設(shè)置。
Flask-Moment 是什么
有一個(gè)使用 JavaScript 開發(fā)的優(yōu)秀客戶端開源代碼庫(kù)房铭,
名為 moment.js( http://momentjs.com/)驻龟,
它可以在瀏覽器中渲染日期和時(shí)間温眉。
Flask-Moment 是一個(gè) Flask 程序擴(kuò)展缸匪,
能把moment.js 集成到 Jinja2 模板中。
如何安裝和初始化
Flask-Moment 可以使用 pip 安裝:
$ pip install flask-moment
from flask_moment import Moment
moment = Moment(app)
除了 moment.js类溢, Flask-Moment 還依賴 jquery.js凌蔬。
要在 HTML 文檔的某個(gè)地方引入這兩個(gè)庫(kù),
可以直接引入闯冷,這樣可以選擇使用哪個(gè)版本砂心,
也可使用擴(kuò)展提供的輔助函數(shù),
從內(nèi)容分發(fā)網(wǎng)絡(luò)( Content Delivery Network蛇耀,
CDN)中引入通過(guò)測(cè)試的版本辩诞。
Bootstrap 已經(jīng)引入了 jquery.js,
因此只需引入 moment.js 即可纺涤。
下面的例子展示了如何在基模板的 scripts 塊中引入這個(gè)庫(kù)译暂。
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }} # 引入moment.js庫(kù)
{% endblock %}
如何使用Flask-Moment
為了處理時(shí)間戳抠忘, Flask-Moment 向模板開放了 moment類。
- hello.py:加入一個(gè)datetime變量外永。
from datetime import datetime
@app.route('/')
def index():
return render_template('index.html',current_time=datetime.utcnow())
- templates/index.html:使用 Flask-Moment 渲染時(shí)間戳
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
format('LLL') 根據(jù)客戶端電腦中的時(shí)區(qū)和區(qū)域設(shè)置渲染日期和時(shí)間崎脉。
參數(shù)決定了渲染的方式,
'L' 到 'LLLL' 分別對(duì)應(yīng)不同的復(fù)雜度伯顶。
format() 函數(shù)還可接受自定義的格式說(shuō)明符囚灼。
第二行中的 fromNow() 渲染相對(duì)時(shí)間戳,
而且會(huì)隨著時(shí)間的推移自動(dòng)刷新顯示的時(shí)間祭衩。
這個(gè)時(shí)間戳最開始顯示為“ a few seconds ago”灶体,
但指定 refresh 參數(shù)后,
其內(nèi)容會(huì)隨著時(shí)間的推移而更新掐暮。 如果一直待在這個(gè)頁(yè)面赃春,
幾分鐘后,會(huì)看到顯示的文本變成“ a minuteago”“ 2 minutes ago”等劫乱。
其他功能
Flask-Moment 渲染的時(shí)間戳可實(shí)現(xiàn)多種語(yǔ)言的本地化织中。
語(yǔ)言可在模板中選擇,把語(yǔ)言代碼
傳給 lang() 函數(shù)即可:
{{ moment.lang("zh_cn") }}
Flask-Moment 實(shí)現(xiàn)了 moment.js 中的 format()衷戈、 fromNow()狭吼、 fromTime()、 calendar()殖妇、 valueOf()和 unix() 方法刁笙。
你可查閱文檔 http://momentjs.com/docs/#/displaying/
學(xué)習(xí) moment.js 提供的全部格式化選項(xiàng)。
Flask-Monet 假定服務(wù)器端程序處理的時(shí)間戳是“純正的” datetime 對(duì)象谦趣,
且使用 UTC 表示疲吸。
關(guān)于純正和細(xì)致的日期和時(shí)間對(duì)象 1 的說(shuō)明,
請(qǐng)閱讀標(biāo)準(zhǔn)庫(kù)中 datetime 包的文檔
https://docs.python.org/2/library/datetime.html