flask學習筆記(-模板)
為什麼使用模板
檢視函式的作用很明確,即生成請求的響應。但 Flask 檢視函式的兩個完全獨立的作用(處理邏輯和頁面)卻被融在一起。
例如,使用者在網站中註冊了一個新賬戶。使用者在表單中輸入電子郵件地址和密碼,然後點選提交按鈕。伺服器接收到包含使用者輸入資料的請求,然後 Flask 把請求分發到處理註冊請求的檢視函式。這個檢視函式需要訪問資料庫,新增新使用者,然後生成響應回送瀏覽器。這兩個過程分別稱為業務邏輯和表現邏輯。
Flask,使用模板將這兩個邏輯分離。這樣檢視函式可以專注於處理業務邏輯,而表現邏輯則交給Flask的Jinjia2的模板引擎來處理。
jinjia2模板引擎
{% … %} for Statements
{{ … }} for Expressions to print to the template output
{# … #} for Comments not included in the template output
# … ## for Line Statements
建立user模板
<h1> Hello, {{ name }}! </h1>
渲染模板
Flask在程式資料夾的templates子資料夾中尋找模板。
渲染模板呼叫:render_template('user.html', var_key=var_value)
變數
{{ name }} 結構表示一個變數,它是一種特殊的佔位符,告訴模板引擎這個位置的值從渲染模板時使用的資料中獲取。
Jinja2 能識別所有型別的變數,甚至是一些複雜的型別,例如列表、字典和物件。
<p>a dictionary: {{ mydict['key'] }}.</p >
<p>a list: {{ mylist[3] }}.</p>
<p>a list, with a variable index: {{ mylist[myintvar] }}.</p>
<p>an object's method: {{ myobj.somemethod() }}.</p>
過濾器變數可以通過 過濾器 修改。過濾器與變數用管道符號( | )分割,並且也 可以用圓括號傳遞可選引數。多個過濾器可以鏈式呼叫,前一個過濾器的輸出會被作為 後一個過濾器的輸入。例如 {{ name|striptags|title }}
會移除 name 中的所有 HTML 標籤並且改寫 為標題樣式的大小寫格式。內建過濾器清單。
控制結構
Jinja2 提供了多種控制結構,可用來改變模板的渲染流程。
- 條件控制。
{ % if user % }
Hello, {{ user }}!
{ % else % }
Hello, Stranger!
{ % endif % }
- 迴圈控制
<ul>
{ % for comment in comments % }
<li>{{ comment }}</li>
{ % endfor % }
</ul>
- 巨集
巨集類似於 Python 程式碼中的函式。
<!--巨集的定義-->
{ % macro render_comment(comment) % }
<li>{{ comment }}</li>
{ % endmacro % }
<!--巨集的使用-->
<ul>
{ % for comment in comments % }
<!--巨集呼叫-->
{{ render_comment(comment) }}
{ % endfor % }
</ul>
- 包含模板
需要在多處重複使用的模板程式碼片段可以寫入單獨的檔案,再包含在所有模板中,以避免重複:
{ % include 'common.html' as common% }
{{common.XXXX}}
- 模板繼承
它類似於 Python 程式碼中的類繼承。
首先,定義基模板。如base.html
<html>
<head>
{ % block head % }
<title>{ % block title % }{ % endblock % } - My Application</title>
{ % endblock % }
</head>
<body>
{ % block body % }
{ % endblock % }
</body>
</html>
定義衍生模板。
{ % extends "base.html" % }
{ % block title % }Index{ % endblock % }
{ % block head % }
{{ super() }}
<style></style>
{ % endblock % }
{ % block body % }
<h1>Hello, World!</h1>
{ % endblock % }
{% extend %} 標籤是這裡的關鍵。它告訴模板引擎這個模板“繼承”另一個模板。 當模板系統對這個模板求值時,首先定位父模板。 extends 標籤應該是模板中的第一個 標籤。它前面的所有東西都會按照普通情況打印出來,而且可能會導致一些困惑。
extends 指令宣告這個模板衍生自 base.html。在 extends 指令之後,基模板中的 3 個塊被重新定義,模板引擎會將其插入適當的位置。注意新定義的 head 塊,在基模板中其內容不是空的,所以使用 super() 獲取原來的內容,呼叫 super 來渲染父級塊的內容。這會返回父級塊的結果。
設計模板
使用Flask-Bootstrap
- 安裝
pip install flask-bootstrap
- 初始化Flask-Bootstrap
from flask.ext.bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之後,就可以在程式中使用一個包含所有 Bootstrap 檔案的基模板。這個模板利用Jinja2的模板繼承機制,讓程式擴充套件一個具有基本頁面結構的基模板,其中就有用來引入 Bootstrap 的元素。官方教程
{% extends "bootstrap/base.html" %}<!--extends 指 令 從 Flask-Bootstrap中匯入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 %}
定義錯誤頁面
如果你在瀏覽器的位址列中輸入了不可用的路由,那麼會顯示一個狀態碼為 404 的錯誤頁面。現在這個錯誤頁面太簡陋、平庸,而且樣式和使用了 Bootstrap 的頁面不一致。
- 定義錯誤處理函式。
與檢視函式類似,只不過使用不同的修飾器@app.errorhandler(error_code)
@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
- 編寫對應的模板檔案
連結
在模板中直接編寫簡單路由的 URL 連結不難,但對於包含可變部分的動態路由,在模板中構建正確的 URL 就很困難。而且,直接編寫 URL 會對程式碼中定義的路由產生不必要的依賴關係。如果重新定義路由,模板中的連結可能會失效。Flask 提供了 url_for() 輔助函式,它可以使用程式 URL 對映中儲存的資訊生成 URL。
靜態檔案
用靜態檔案,例如 HTML程式碼中引用的圖片、JavaScript 原始碼檔案和 CSS。預設設定下,Flask 在程式根目錄中名為 static 的子目錄中尋找靜態檔案。如果需要,可在static 資料夾中使用子資料夾存放檔案。
如索引圖示的位置{{ url_for('static', filename = 'favicon.ico') }}
Flask-Moment本地化日期和時間
- 安裝
pip install flask-moment
- 初始化
from flask.ext.moment import Moment
moment = Moment(app)
- 引入 moment.js 庫
{ % block scripts % }
{{super()}}
{{moment.include_moment() }}
{ %endblock % }
- 加入一個 datetime 變數
from datetime import 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>