Flask Web Development 第三章讀書筆記 模板

第三章 模板

為什么要分離

易于維護(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末前鹅,一起剝皮案震驚了整個(gè)濱河市摘悴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舰绘,老刑警劉巖蹂喻,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異捂寿,居然都是意外死亡口四,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門秦陋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蔓彩,“玉大人,你說(shuō)我怎么就攤上這事〕嘟溃” “怎么了大磺?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)探膊。 經(jīng)常有香客問(wèn)我杠愧,道長(zhǎng),這世上最難降的妖魔是什么逞壁? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任流济,我火速辦了婚禮,結(jié)果婚禮上腌闯,老公的妹妹穿的比我還像新娘绳瘟。我一直安慰自己,他們只是感情好姿骏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布糖声。 她就那樣靜靜地躺著,像睡著了一般分瘦。 火紅的嫁衣襯著肌膚如雪蘸泻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天嘲玫,我揣著相機(jī)與錄音悦施,去河邊找鬼。 笑死去团,一個(gè)胖子當(dāng)著我的面吹牛抡诞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播土陪,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昼汗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鬼雀?” 一聲冷哼從身側(cè)響起顷窒,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎取刃,沒(méi)想到半個(gè)月后蹋肮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡璧疗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馁龟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崩侠。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坷檩,靈堂內(nèi)的尸體忽然破棺而出却音,到底是詐尸還是另有隱情改抡,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布系瓢,位于F島的核電站阿纤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夷陋。R本人自食惡果不足惜欠拾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骗绕。 院中可真熱鬧藐窄,春花似錦、人聲如沸酬土。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撤缴。三九已至刹枉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屈呕,已是汗流浹背嘶卧。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凉袱,地道東北人芥吟。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像专甩,于是被迫代替她去往敵國(guó)和親钟鸵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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