Flask框架基礎(二)
##1 程式的基本結構 ###1.1初始化 所有Flask 程式都必須建立一個程式例項。Web 伺服器使用一種名為Web 伺服器閘道器介面(Web Server Gateway Interface,WSGI)的協議,把接收自客戶端的所有請求都轉交給這個物件處理。程式例項是Flask 類的物件。
from flask import Flask
app = Flask(__name__)
傳入Flask構造方法的第一個引數是模組或者包的名稱,我們應該使用特殊變數 __name __。 Python會根據所處的模組來賦予 __ name __變數相應的值,對於我們程式來說,這個值為app ###1.2註冊路由 客戶端(例如Web 瀏覽器)把請求傳送給Web 伺服器,Web 伺服器再把請求傳送給Flask 程式例項。程式例項需要知道對每個URL 請求執行哪些程式碼,所以儲存了一個URL 到Python 函式的對映關係。處理URL 和函式之間關係的程式稱為路由。
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
在這個程式中,app.route()裝飾器把根地址/和index()函式繫結起來,當用戶訪問這個URL時就會觸發index()函式。檢視函式index()返回 " Hello World! "
route()裝飾器的第一個引數是URL規則,用字串表示,必須以/開始。這裡的URL是相對的URL(又稱內部URL),即不包含域名的URL,以域名www.google.com為例,“/”對應的是根地址,即www.google.com,如果把URL規則改為“/maps”,則實際的絕對地址為
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
###1.3啟動伺服器 程式例項用run 方法啟動Flask 整合的開發Web 伺服器:
if __name__ == '__main__':
app.run(debug=True)
__ name__==’__ main__'是Python 的慣常用法,在這裡確保直接執行這個指令碼時才啟動開發Web 伺服器。如果這個指令碼由其他指令碼引入,程式假定父級指令碼會啟動不同的伺服器,因此不會執行app.run()。 ###1.4完整的程式
示例1.4 hello.py:一個完整的Flask 程式
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
if __name__ == '__main__':
app.run(debug=True)
###1.4 異常捕獲 使用裝飾器的形式去捕獲指定的錯誤碼和異常
@app.errorhandler(404)
def page_not_found(error):
return '404'
###1.5請求鉤子 為了讓每個檢視函式避免編寫重複功能的程式碼,Flask提供了通用設施的功能,即請求鉤子。 請求鉤子是通過裝飾器的形式實現,Flask支援如下四種請求鉤子:
- before_first_request:註冊一個函式,在處理第一個請求之前執行。
- before_request:註冊一個函式,在每次請求之前執行。
- after_request:註冊一個函式,如果沒有未處理的異常丟擲,在每次請求之後執行。
- teardown_request:註冊一個函式,即使有未處理的異常丟擲,也在每次請求之後執行。 – ##2 模板 模板是一個包含響應文字的檔案,其中包含用佔位變量表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實值替換變數,再返回最終得到的響應字串,這一過程稱為渲染。為了渲染模板,Flask 使用了一個名為Jinja2 的強大模板引擎。 ###2.1 Jinja2模板引擎
- Jinjia2是由python實現的
- 是Flask內建的模板語言
- 參照Django設計思想設計的,跟Django差不多 ####2.1.1渲染模板 預設情況下,Flask 在程式資料夾中的templates 子資料夾中尋找模板。Flask提供的
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)
示例 templates/index.html:Jinja2 模板
<h1>Hello World!</h1>
示例
<h1>Hello, {{ name }}!</h1>
render_template 函式封裝了該模板引擎 render_template 函式的第一個引數是模板的檔名,後面的引數都是鍵值對,表示模板中變數對應的真實值
###2.1.2 變數 在模板中使用的{{ name }} 結構表示一個變數,它是一種特殊的佔位符,告訴模 板引擎這個位置的值從渲染模板時使用的資料中獲取。
可以使用過濾器修改變數,過濾器名新增在變數名之後,中間使用豎線分隔。例如,下述模板以首字母大寫形式顯示變數name 的值:
Hello, {{ name|capitalize }}
Jinja2 提供的部分常用過濾器
表 Jinja2變數過濾器
過濾器名 | 說明 |
---|---|
safe | 渲染值時不轉義 |
capitalize | 把值的首字母轉換成大寫,其他字母轉換成小寫 |
lower | 把值轉換成小寫形式 |
upper | 把值轉換成大寫形式 |
title | 把值中每個單詞的首字母都轉換成大寫 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML 標籤都刪掉 |
###2.1.3 控制結構 Jinja2 提供了多種控制結構,可用來改變模板的渲染流程。
- 條件控制:
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
- 迴圈控制:
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
- 巨集
<!--巨集的定義-->
{ % macro render_comment(comment) % }
<li>{{ comment }}</li>
{ % endmacro % }
<!--巨集的使用-->
<ul>
{ % for comment in comments % }
<!--巨集呼叫-->
{{ render_comment(comment) }}
{ % endfor % }
</ul>
####模板程式碼複用 在模板中,可能會遇到以下問題
-
多個模板具有完全相同的頂部和底部內容
-
多個模板中具有相同的模板程式碼內容,但是內容中部分值不一樣
-
多個模板中具有完全相同的 html 程式碼塊內容
像遇到這種情況,可以使用 JinJa2 模板中的 巨集、繼承、包含來進行實現
#####模板繼承
標籤定義的內容
{% block %} {% endblock %}
模板繼承是為了重用模板中的公共內容。一般Web開發中,繼承主要使用在網站的頂部選單、底部。這些內容可以定義在父模板中,子模板直接繼承,而不需要重複書寫。
首先建立一個名為base.html 的基模板
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
block 標籤定義的元素可在衍生模板中修改。在本例中,我們定義了名為head、title 和 body 的塊。注意,title 包含在head 中。下面這個示例是基模板的衍生模板:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
extends 指令宣告這個模板衍生自base.html。在extends 指令之後,基模板中的3 個塊被 重新定義,模板引擎會將其插入適當的位置。注意新定義的head 塊,在基模板中其內容不 是空的,所以使用super() 獲取原來的內容。 ###2.2 Flask-Bootstrap Bootstrap(http://getbootstrap.com/)是Twitter 開發的一個開源框架,它提供的使用者介面組 件可用於建立整潔且具有吸引力的網頁,而且這些網頁還能相容所有現代Web 瀏覽器。 Bootstrap 是客戶端框架,因此不會直接涉及伺服器。伺服器需要做的只是提供引用了 Bootstrap 層疊樣式表(CSS) 和JavaScript 檔案的HTML 響應, 並在HTML、CSS 和 JavaScript 程式碼中例項化所需元件。這些操作最理想的執行場所就是模板。
- 初始化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 %}
###2.3 自定義錯誤頁面 像常規路由一樣,Flask 允許程式使用基於模板的自定義錯誤頁面。最常見的錯誤程式碼有 兩個:404,客戶端請求未知頁面或路由時顯示;500,有未處理的異常時顯示。
@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
###2.4 連結
在模板中直接編寫簡單路由的 URL 連結不難,但對於包含可變部分的動態路由,在模板中構建正確的 URL 就很困難。而且,直接編寫 URL 會對程式碼中定義的路由產生不必要的依賴關係。如果重新定義路由,模板中的連結可能會失效。Flask 提供了 url_for() 輔助函式,它可以使用程式 URL 對映中儲存的資訊生成 URL。
###2.5 靜態檔案
用靜態檔案,例如 HTML程式碼中引用的圖片、JavaScript 原始碼檔案和 CSS。預設設定下,Flask 在程式根目錄中名為 static 的子目錄中尋找靜態檔案。如果需要,可在static 資料夾中使用子資料夾存放檔案。
如索引圖示的位置{{ url_for('static', filename = 'favicon.ico') }}