本系列筆記是我閱讀Miguel Grinberg的《Flask Web Development》的筆記,標題與書本同步。希望通過記錄技術筆記的方式促進自己對知識的理解。
本篇對應書本第三章:模板。
模板是一個包含響應文字的檔案,其中包含用佔位變數表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實值替代變數,再返回最終得到的響應字串,這一過程成為渲染。
Jinja2模板引擎
Flask渲染模板使用的是Jinja2模板引擎。
渲染模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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) # Flask提供的render_template函式把Jinja2模板引擎整合到了程式中。 # render_template函式的第一個引數是模板的檔名。 # 隨後的引數都是鍵值對,表示模板中變數對應的真實值。 |
變數
模板中使用的{{ name }}結構表示一個變數,它是一種特殊的佔位符,告訴模組引擎這個位置的值從渲染模板時使用的資料中獲取。
Jinja2能識別所有型別的變數,示例:
1 2 3 4 |
<p>A value from a dictionary:{{ mydict['key']}}.</p> <p>A value from a list:{{ mylist[3]}}.</p> <p>A value from a list,with a variable index:{{ mylist[myintvar] }}.</p> <p>A value from an object's method: {{ myobj.somemethod() }}.</p> |
變數過濾器
過濾器名新增在變數之後,中間使用豎線分隔。
1 |
hello, {{ name|capitalize }} |
常用過濾器:
過濾器名 | 說明 |
---|---|
safe | 渲染值時不轉義 |
capitalize | 把值得首字母轉換成大寫,其他字母轉換成小寫 |
lower | 把值轉換成小寫形式 |
upper | 把值轉換成大寫形式 |
title | 把值中每個單詞的首字母都換成大寫 |
trim | 把值的首位空格去掉 |
striptags | 渲染之前把值中所有的HTML標籤都刪掉 |
控制結構
條件控制結構
1 2 3 4 5 6 |
{% if user %} Hello,{{ user }}! {% else %} Hello, Stranger! {% endif %} |
渲染一組元素
1 2 3 4 5 |
<ul> {% for comment in comments %} <li>{{ comment }}</li> {% endfor %} </ul> |
巨集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{{% macro render_comment(comment)%}} <li>{{ comment }}</li> {{ endmacro }} <ul> {% for comment in comments %} {{ render_comment(comment) }} {% endfor %} </ul> 為了重複使用巨集,儲存在單獨檔案中,再在需要的模板中匯入。 {% import 'macro.html' as macros %} <ul> {% for comment in comments%} {{ macros.render_comment(comment)}} {% endfor%} </ul> |
複用程式碼片段
1 2 |
{% include 'common.html' %} |
模板繼承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
- 建一個名為base.html的基模板 <html> <head> {% block head %} <title>{% block title %}{% endblock %} - My Application</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> - 衍生模板中修改block標籤定義的元素 {% extends "base.html" %} #定義基模板 {% block title%}Index{% endblock %} #修改title塊內容 {% block head %} #修改head塊內容 {{ super() }} #原來head中有內容,用super()獲取原來的內容 <style> </style> {% endblock %} {% block body %} #修改body塊內容 <h1>Hello, World!</h1> {% endblock %} |
使用Flask-Bootstrap整合Twitter Bootstrap
Bootstrap是Twitter開發的一個開源框架,它提供使用者介面元件可用於建立整潔且具有吸引力的網頁,而且這些網頁還能相容所有現代Web瀏覽器。Bootstrap是客戶端框架,不會直接涉及伺服器。可以在模板中引用Bootstrap的CSS和JavaScript檔案。
安裝Flask-Bootstrap擴充套件
1 2 3 4 5 6 7 |
(venv)$ pip install flask-bootstrap hello.py: 初始化Flask-Bootstrap from falsk_bootstrap import Bootstrap # ... bootstrap = Bootstrap(app) |
使用Flask-Bootstrap的模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
{% 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="/"></a></li> </ul> </div> </div> </div> {% endblock %} {% block content %} <div class="container"> <div class="page-header"> <h1>Hello,{{ name }}!</h1> </div> </div> {% endblock %} # 模板利用Bootstrap中的樣式進行了修改 |
Flask-Bootstrap基模板中定義的塊
塊名 | 說明 |
---|---|
doc | 整個HTML文件 |
html_attribs | <html>標籤的屬性 |
html | <html>標籤中的內容 |
head | <head>標籤中的內容 |
title | <title>標籤中的內容 |
metas | 一組標籤 |
styles | 層疊樣式表定義 |
body_attribs | <body>標籤的屬性 |
body | <body>標籤中的內容 |
navbar | 使用者定義的導航條 |
content | 使用者定義的頁面內容 |
scripts | 文件底部的JavaScript宣告 |
自定義錯誤頁面
利用Jinja2的模板繼承機制可以讓templates/base.html繼承自bootstrap/base.html。
12345678910111213141516171819202122232425262728293031 {% 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 %}程式現在使用的模板繼承自templates/base.html不是直接繼承自Flask-Bootstrap的基模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
404錯誤頁面:繼承自templates/base.html {% extends "base.html" %} {% block title %}Flasky - Page Not Found{% endblock %} {% block page_content %} <div class="page-header"> <h1>Not Found</h1> </div> {% endblock %} user頁面:繼承自templates/base.html {% extends "base.html" %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class="page-header"> <h1>Hello, {{ name }}!</h1> </div> {% endblock %} |
連結
Flask提供了url_for()輔助函式,它可以使用程式URL對映中儲存的資訊生成URL。
- url_for函式最簡單的用法:以檢視函式名作為引數,返回對應的URL。url_for(‘index’)得到的結果是’/’
- 使用url_for生成動態地址時,將動態部分作為關鍵字引數傳入。
url_for(‘user’,name=’john’,_external=True) - 函式能將任何額外引數新增到查詢字串中。
靜態檔案
使用Flask-Moment本地化日期和時間
Flask-Moment是Flask的一個程式擴充套件,能夠在瀏覽器中渲染日期和時間。
安裝Flask-Moment
1 2 |
(venv)$ pip install flask-moment |
hello.py:初始化Flask-Moment
1 2 3 |
from flask_moment import Moment moment = Moment(app) |
templates/base.html: 引入 moment.js庫
1 2 3 4 5 |
{% block scripts %} {{ super() }} {{ moment.include_moment() }} {% endblock %} |
hello.py: 加入一個datetime變數
1 2 3 4 5 6 |
from date.time import datetime @app.route('/') def index(): return render_template('index.html',current_time=datetime.utcnow()) |
templates/index.html: 使用Flask-Moment渲染時間戳
1 2 |
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p> <p>That was {{ moment(current_time).fromNow(refresh=True) }}.</p> |