03.flask模板
模板概述
一. 為什麼要使用模板
檢視函式有兩個作用, 一個是業務邏輯一個是表現邏輯, 舉例說明:
使用者在網站註冊了一個新賬號, 使用者在表單中輸入電子郵件地址和密碼, 點選提交按鈕, 伺服器接收到包含使用者輸入的請求, 然後Flask把請求分發到處理註冊請求的檢視函式。 這個檢視函式需要訪問資料庫, 新增新使用者(業務邏輯), 然後生成相應回送瀏覽器(表現邏輯)。
兩個完全獨立的作用被混淆到一起會使程式碼難以理解和維護, 所以我們選擇把表現邏輯(響應)遷移到模板當中去。
模板是包含響應文字的檔案,其中包含用佔位變量表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實值替換變數,再返回最終得到的響應字串,這一過程稱為渲染。為了渲染模板,Flask 使用一個名為 Jinja2 的強大模板引擎。
二. 如何使用模板
- 如何渲染模板:
- 模板放在
templates
資料夾下 - 從
flask
中匯入render_template
函式。 - 在檢視函式中,使用
render_template
函式,渲染模板。注意:只需要填寫模板的名字,不需要填寫templates
這個資料夾的路徑。
- 模板放在
- 模板傳參:
- 如果只有一個或者少量引數,直接在
render_template
函式中新增關鍵字引數就可以了。 - 如果有多個引數的時候,那麼可以先把所有的引數放在字典中,然後在
render_template
中,
使用兩個星號,把字典轉換成關鍵引數傳遞進去,這樣的程式碼更方便管理和使用。
- 如果只有一個或者少量引數,直接在
- 在模板中,如果要使用一個變數,語法是:
{{params}}
- 訪問模型中的物件屬性或者是字典,可以通過
{{params.property}}
的形式,或者是使用{{params['age']}}
.
示例程式碼
template01 .py
#encoding: utf-8 from flask import Flask,render_template app = Flask(__name__) @app.route('/') def index(): # 類 class Person(object): name = u'p17bdw' age = 18 p = Person() context = { 'username': u'c17bdw', 'gender': u'男', 'age': 17, 'person': p, # 宣告 'websites': { 'baidu': 'www.baidu.com', 'google': 'www.google.com' } } return render_template('anthoer/index.html',**context) if __name__ == '__main__': app.run(debug=True)
anthoer/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
這是HTML檔案中出現的文字
<p>使用者名稱:{{ username }}</p>
<p>性別:{{ gender }}</p>
<p>年齡:{{ age }}</p>
<hr>
<p>名字:{{ person['name'] }}</p>
<p>年齡:{{ person.age }}</p>
<hr>
<p>百度:{{ websites['baidu'] }}</p>
<p>谷歌:{{ websites['google'] }}</p>
</body>
</html>
if判斷
-
語法:
{% if xxx %} {% else %} {% endif %}
-
if的使用,可以和python中相差無幾。
示例程式碼
if_statement .py
# 輸入 http://127.0.0.1:5000/1/ 為登入狀態,否則為未登入狀態。
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/<is_login>/')
def index(is_login):
if is_login == '1':
user = {
'username': u'17bdw',
'age':20
}
return render_template('index.html',user=user)
else:
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% if user and user.age > 18 %}
<a href="#">{{ user.username }}</a>
<a href="#">登出</a>
{% else %}
<a href="#">登入</a>
<a href="#">註冊</a>
{% endif %}
</body>
</html>
for迴圈遍歷列表和字典
1. 字典的遍歷,語法和`python`一樣,可以使用`items()`、`keys()`、`values()`、`iteritems()`、`iterkeys()`、`itervalues()`
`{% for k,v in user.items() %} <p>{{ k }}:{{ v }}</p> {% endfor %}`
2. 列表的遍歷:語法和`python`一樣。
`{% for website in websites %} <p>{{ website }}</p> {% endfor %}`
示例程式碼
for_statement .py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
# for遍歷字典
@app.route('/')
def index():
books = [
{
'name': u'西遊記',
'author': u'吳承恩',
'price': 109
},
{
'name': u'紅樓夢',
'author': u'曹雪芹',
'price': 200
},
{
'name': u'三國演義',
'author': u'羅貫中',
'price': 120
},
{
'name': u'水滸傳',
'author': u'施耐庵',
'price': 130
}
]
return render_template('index.html',books=books)
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<thead>
<th>書名</th>
<th>作者</th>
<th>價格</th>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
過濾器
-
介紹和語法:
- 介紹:過濾器可以處理變數,把原始的變數經過處理後再展示出來。作用的物件是變數。
- 語法:
{{ avatar|default('xxx') }}
-
default過濾器:如果當前變數不存在,這時候可以指定預設值。
-
length過濾器:求列表或者字串或者字典或者元組的長度。
-
常用的過濾器:
abs(value):返回一個數值的絕對值。示例:-1|abs
default(value,default_value,boolean=false):如果當前變數沒有值,則會使用引數中的值來代替。示例:name|default('xiaotuo')——如果name不存在,則會使用xiaotuo來替代。boolean=False預設是在只有這個變數為undefined的時候才會使用default中的值,如果想使用python的形式判斷是否為false,則可以傳遞boolean=true。也可以使用or來替換。
escape(value)或e:轉義字元,會將<、>等符號轉義成HTML中的符號。示例:content|escape或content|e。
first(value):返回一個序列的第一個元素。示例:names|first
last(value):返回一個序列的最後一個元素。示例:names|last。length(value):返回一個序列或者字典的長度。示例:names|length。
join(value,d=u''):將一個序列用d這個引數的值拼接成字串。
safe(value):如果開啟了全域性轉義,那麼safe過濾器會將變數關掉轉義。示例:content_html|safe。
int(value):將值轉換為int型別。
float(value):將值轉換為float型別。
lower(value):將字串轉換為小寫。
upper(value):將字串轉換為小寫。
replace(value,old,new): 替換將old替換為new的字串。
truncate(value,length=255,killwords=False):擷取length長度的字串。
striptags(value):刪除字串中所有的HTML標籤,如果出現多個空格,將替換成一個空格。
trim:擷取字串前面和後面的空白字元。
string(value):將變數轉換成字串。
wordcount(s):計算一個長字串中單詞的個數。
示例程式碼
filter_demo .py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
comments = [
{
'user': u'admin',
'content': 'xxxx'
},
{
'user': u'tesr',
'content': 'xxxx'
}
]
return render_template('index.html',comments=comments)
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>過濾器</title>
</head>
<body>
# 如果avatar這個變數不存在,就使用default過濾器提供的值
<img src="{{ avatar|default('http://avatar.csdn.net/1/D/B/3_hmzkekek41.jpg') }}" alt="">
<hr>
# length 計算長度
<p>評論數:({{ comments|length }})</p>
<ul>
{% for comment in comments %}
<li>
<a href="#">{{ comment.user }}</a>
<p>{{ comment.content }}</p>
</li>
{% endfor %}
</ul>
</body>
</html>
繼承和block
-
繼承作用和語法:
- 作用:可以把一些公共的程式碼放在父模板中,避免每個模板寫同樣的程式碼。
- 語法:
{% extends 'base.html' %}
-
block實現:
- 作用:可以讓子模板實現一些自己的需求。父模板需要提前定義好。
- 注意點:字模板中的程式碼,必須放在block塊中。
示例程式碼
app.py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login/')
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run(debug=True)
index.html
{% extends 'base.html' %}
{% block head %}
<style>
</style>
<link rel="stylesheet" href="">
<script></script>
{% endblock %}
{% block title %}
首頁
{% endblock %}
{% block main %}
<h1>這是首頁</h1>
{% endblock %}
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<style>
.nav{
background: #3a3a3a;
height: 65px;
}
ul{
overflow: hidden;
}
ul li{
float: left;
list-style: none;
padding: 0 10px;
line-height: 65px;
}
ul li a{
color: #fff;
}
</style>
{% block head %}{% endblock %}
</head>
<body>
<div class="nav">
<ul>
<li><a href="/">首頁</a></li>
<li><a href="/login">釋出問答</a></li>
</ul>
</div>
{% block main %}{% endblock %}
</body>
</html>
login.html
{% extends 'base.html' %}
{% block title %}
登入
{% endblock %}
{% block main %}
<h1>這是登入頁面</h1>
{% endblock %}
使用Flask-Bootstrap整合Bootstrap
Bootstrap 是 Twitter 開發的一個開源 Web 框架,它提供的使用者介面元件可用於建立整潔且具有吸引力的網頁,而且相容所有現代的桌面和移動平臺 Web 瀏覽器。
要想在應用中整合 Bootstrap,最直接的方法是根據 Bootstrap 文件中的說明對 HTML 模板進行必要的改動。不過,這個任務使用 Flask擴充套件處理要簡單得多,而且相關的改動不會導致主邏輯凌亂不堪。
我們要使用的擴充套件是 Flask-Bootstrap,它可以使用 pip 安裝:
(venv) $ pip install flask-bootstrap
Flask 擴充套件在建立應用例項時初始化。
初始化 Flask-Bootstrap。
from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
擴充套件通常從flask_<name>
包中匯入,其中<name>
是擴充套件的名稱。多數 Flask 擴展采用兩種初始化方式中的一種。在示例中,初始化擴充套件的方式是把應用例項作為引數傳給建構函式。
初始化 Flask-Bootstrap 之後,就可以在應用中使用一個包含所有 Bootstrap 檔案和一般結構的基模板。應用利用 Jinja2 的模板繼承機制來擴充套件這個基模板。
templates/user.html:使用 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 %}
Jinja2 中的extends
指令從 Flask-Bootstrap 中匯入 bootstrap/base.html,從而實現模板繼承。Flask-Bootstrap 的基模板提供了一個網頁骨架,引入了 Bootstrap 的所有 CSS 和 JavaScript 檔案。
上面這個 user.html 模板定義了 3 個區塊,分別名為title
、navbar
和content
。這些區塊都是基模板提供的,可在衍生模板中重新定義。title
區塊的作用很明顯,其中的內容會出現在渲染後的 HTML 文件頭部,放在<title>
標籤中。navbar
和content
這兩個區塊分別表示頁面中的導航欄和主體內容。
在這個模板中,navbar
區塊使用 Bootstrap 元件定義了一個簡單的導航欄。content
區塊中有個<div>
容器,其中包含一個頁頭。之前版本中的歡迎訊息,現在就放在這個頁頭裡。改動之後的應用如圖所示。
url連結
使用url_for(檢視函式名稱)
可以反轉成url。
在模板中直接編寫簡單路由的 URL 連結不難,但對於包含可變部分的動態路由,在模板中構建正確的 URL 就很困難了。而且,直接編寫 URL 會對程式碼中定義的路由產生不必要的依賴關係。如果重新定義路由,模板中的連結可能會失效。
為了避免這些問題,Flask 提供了 url_for() 輔助函式,它使用應用的 URL 對映中儲存的資訊生成 URL。
url_for() 函式最簡單的用法是以檢視函式名作為引數,返回對應的 URL。例如,在當前版本的 app.py 應用中呼叫 url_for('index') 得到的結果是 /,即應用的根 URL。呼叫 url_for('index', _external=True) 返回的則是絕對地址,在這個示例中是 http://localhost:5000/。
使用 url_for() 生成動態 URL 時,將動態部分作為關鍵字引數傳入。例如,url_for('user', name='john', _external=True) 的返回結果是 http://localhost:5000/user/john。
傳給 url_for() 的關鍵字引數不僅限於動態路由中的引數,非動態的引數也會新增到查詢字串中。例如,url_for('user', name='john', page=2, version=1) 的返回結果是 /user/ john?page=2&version=1。
載入靜態檔案
Web 應用不是僅由 Python 程式碼和模板組成。多數應用還會使用靜態檔案,例如模板中 HTML 程式碼引用的影象、JavaScript 原始碼檔案和 CSS。
在前一章中審查 app.py 應用的 URL 對映時,其中有一個 static 路由。這是 Flask 為了支援靜態檔案而自動新增的,這個特殊路由的 URL 是 /static/
預設設定下,Flask 在應用根目錄中名為 static 的子目錄中尋找靜態檔案。如果需要,可在 static 資料夾中使用子資料夾存放檔案。伺服器收到對映到 static 路由上的 URL 後,生成的響應包含檔案系統中對應檔案裡的內容。
- 語法:
url_for('static',filename='路徑')
- 可以載入
css
檔案,可以載入js
檔案,還有image
檔案。
第一個:載入css檔案
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}">
第二個:載入js檔案
<script src="{{ url_for('static',filename='js/index.js') }}"></script>
第三個:載入圖片檔案
<img src="{{ url_for('static',filename='images/zhiliao.png') }}" alt="">