配套視頻教程
模板概述
一. 為什么要使用模板
視圖函數有兩個作用, 一個是業務邏輯一個是表現邏輯, 舉例說明:
用戶在網站注冊了一個新賬號, 用戶在表單中輸入電子郵件地址和密碼, 點擊提交按鈕, 服務器接收到包含用戶輸入的請求, 然后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="">