Flask Web Development 第一章第二章讀書筆記 程序的基本結(jié)構(gòu)

第二章 程序的基本結(jié)構(gòu)

2.1 Flask簡介

Flask框架由三部分組成,F(xiàn)lask、Werkzeug、Jinja2。

Flask,為了提高自由度和可擴展性。只提供網(wǎng)絡框架的最小核心,其他功能則通過擴展實現(xiàn)。它依賴于下面兩個同樣由Flask作者開發(fā)的python模塊。
Werkzeug,一個WSGI框架,它是HTTP可以理解的信息和python程序可以理解的信息之間的翻譯官。通過它Flask程序可以順暢的閱讀HTTP信息。
Jinja2,一個html模板系統(tǒng),它的目的是簡化html語句的錄入工作量。

2.2初始化

2.2.1 Flask類必須指定根目錄參數(shù)

from flask import Flask
app = Flask(__name__)

這是為了能夠找到資源文件。
參數(shù)提供了程序根目錄位置。資源文件一般在根目錄的相對位置。
在大多數(shù)情況下,name這個參數(shù)就是所需值。這個參數(shù)此處的功能是:指向用它做參數(shù)的flask類的目錄,而不管這個類是直接執(zhí)行或被導出調(diào)用。

2.3 路由

2.3.1 Flask需要知道/index這樣的路徑實現(xiàn)什么功能

@app.route('/index')
def index():
    return '<h1>Hell world!</h1>'

路由使用app.route裝飾器,它為路徑/index找到對應的函數(shù),也就是這里的index。

2.3.2 動態(tài)路徑:有時候路徑只有一部分相同,另一部分可變

@app.route('/user/<name>')
def user(name):
    return'<h1>hello, %s!</h1>' % name

尖括號中的內(nèi)容就是動態(tài)部分,任何能匹配靜態(tài)部分的URL都會映射到這個路由上。
調(diào)用視圖函數(shù)時,F(xiàn)lask會將動態(tài)部分作為參數(shù)傳入函數(shù)。

2.3.3 動態(tài)類型定義:

分為int、float、path三種。
例如:/user/<int:id>,只會匹配id為整數(shù)的URL。
path類型也是字符串,但不把斜線視作分隔符,而將其當作動態(tài)片段的一部分。

2.3.4 啟動服務器:使用程序?qū)嵗膔un方法

if __name__ = '__main__':
    app.run(debug=True)

如果這個腳本由其他腳本導入,程序會假定父腳本會啟動不同的服務器。

2.4 完整的例子

2.4.1 一個完整的程序

# 示例 2-1 hello.py: 一個完整的Flask程序
from flask import Flask
app = Flask(__name__)  
 
@app.route('/')
def index():
    return '<h1>Hello World!</h1>'
 
if __name__ == '__main__':
    app.run(debug=True)

使用命令$ python hello.py啟動程序,訪問地址http://localhost:5000/

2.4.2 動態(tài)路由版

# 示例 2-2 hello.py: 包含動態(tài)路由的 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)

訪問 http://localhost:5000/user/Dave
Dave就是動態(tài)參數(shù)<name>,嘗試使用不同的名字試試。

2.5 請求-響應循環(huán)

2.5.1 上下文:防止程序參數(shù)冗余

為什么需要上下文:

Flask需要根據(jù)網(wǎng)址返回相應值,這需要視圖函數(shù)訪問一些對象。
例如request對象,它封裝了客戶端發(fā)送的HTTP請求。
要想讓視圖函數(shù)能夠訪問請求對象,
一個顯而易見的方式是將其作為參數(shù)傳入視圖函數(shù),
不過這會導致程序中的每個視圖函數(shù)都增加一個參數(shù),大大增加復雜度。
Flask使用上下文臨時把某些對象變?yōu)槿肿兞浚@使得視圖函數(shù)不需要顯式聲明這個參數(shù),
但卻能夠使用它,大大降低了復雜度。

一個request使用示例:

from flask import request  
 
@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')
    return '<p>Your brower is %s</p>' % user_agent

=服務器中可能有多個客戶端請求,把request作為全局變量會出錯,
而上下文管理使得request可以全局訪問,但又不干擾其他線程。

上下文全局變量:

current_app  # 當前激活程序的程序?qū)嵗?例如運行的是hello.py,則current_app為<Flask hello>
g  # 處理請求時用作臨時存儲的對象。每次請求都會重設這個變量
request  # 請求對象,封裝了客戶端發(fā)出的HTTP請求中的內(nèi)容
session  # 用戶對話,用于存儲請求之間需要“記住”的值的詞典  

上下文調(diào)用流程:

from hello import app  
from flask import current_app  # 導入需要使用的上下文    
 
app_ctx = app.app_context()  # 激活上下文,取得app_context類的一個實例  
app_ctx.push()  # 推送上下文  
print(current_app.name)  # 在線程中使用導入的上下文。  
app_ctx.pop()  # 手動刪除上下文

flask以app._context類的方法push和pop進出棧的方式,管理多線程。
為防止push棧后,不能pop棧,盡量使用try和finnally.

2.5.2 查看映射:

Flask使用app.route裝飾器或app.add_url_rule()生成映射。
在python shell中使用app.url_map查看映射關(guān)系

>>>from hello import app
>>>app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])  

除了我們自己定義的//user/<name>路由,
還有一個/static/<filename>是Flask添加的靜態(tài)文件路由。顯然<filename>是我們講過的動態(tài)路由中的path類型。

URL 映射中的HEAD、Options、GET 是請求方法,由路由進行處理。
Flask 為每個路由都指定了請求方法,這樣不同的請求方法發(fā)送到相同的 URL 上時,會使用不同的視圖函數(shù)進行處理。
HEAD 和 OPTIONS 方法由 Flask自動處理,因此可以這么說,在這個程序中, URL映射中的 3 個路由都使用 GET 方法。

2.5.3 請求鉤子:避免請求前后的重復操作

請求鉤子是裝飾器,F(xiàn)lask支持4種鉤子:

  • before_first_request:注冊一個函數(shù),在處理第一個請求之前運行。
  • before_request:注冊一個函數(shù),在每次請求之前運行。
  • after_request:注冊一個函數(shù),如果沒有未處理的異常拋出,在每次請求之后運行。
  • teardown_request:注冊一個函數(shù),即使有未處理的異常拋出,也在每次請求之后運行。

在請求函數(shù)和視圖函數(shù)之間共享數(shù)據(jù)一般使用上下文全局變量g。

2.5.4 響應:幾種返回類型和狀態(tài)碼

響應是什么?

Flask調(diào)用視圖函數(shù)后,會將其返回值作為響應的內(nèi)容。
返回值由三部分組成:字符串、狀態(tài)碼和header字典。
大多數(shù)情況下,響應只需要字符串,作為HTML頁面回送客戶端。
但如果不是請求成功處理的正常狀態(tài),就需要增加狀態(tài)碼。
header字典有時也會用到。

請求成功和請求無效的狀態(tài)碼

@app.route('/')
def index():
    return '<h1>Bad Request</h1>', 400

數(shù)字代碼作為第二個返回值,代表處理狀態(tài)。
400代表請求無效,而200代表請求已被成功處理。
Flask把狀態(tài)碼默認設置為200,所以成功處理可以不指定狀態(tài)碼。

重定向的狀態(tài)碼和簡化處理:

有時返回值不是一個頁面字符串,而是一個新地址,這叫做重定向。
重定向經(jīng)常使用302表示,指向的地址由header Location提供。
由于使用頻繁,F(xiàn)lask提供了簡化處理的形式:redirect函數(shù)

from flask import redirect
  
@app.route('/')
def index():
    return redirect('http://www.example.com')

處理錯誤狀態(tài)碼的abort函數(shù):

HTTP有很多種錯誤,F(xiàn)lask用一個通用 的方法abort來處理。
這是所有錯誤代碼:HTTP錯誤代碼

一個abort的例子:

from flask import abort
 
@app.route('/user/<id>')
def get_user(id):
    user = load_user(id)  # 讀取動態(tài)參數(shù)id對應的用戶
    if not user:  # 如果用戶不存在,則返回狀態(tài)碼404
        abort(404)
    return '<h1>Hello, %s</h1> % user.name

2.6 Flask 擴展

2.6.1 為什么需要擴展

Flask被設計為更自由的方式,故沒有提供一些重要的功能,例如數(shù)據(jù)庫和用戶認證。
這就需要用擴展的形式來補充Flask源碼沒有的功能,
開發(fā)者可以自由選擇最適合程序的包,或者按需求自行開發(fā)(可以使用所有python標準包或代碼庫。

2.6.2 使用Flask-Script支持命令行選項

為什么需要命令行選項

Flask的開發(fā)web服務器支持很多啟動設置選項,
但只能在腳本中作為參數(shù)傳給app.run()函數(shù)。
這中方式并不十分方便,傳遞設置選項的理想方式是使用命令行參數(shù)。

Flask-Script介紹和安裝

Flask-Script是一個Flask擴展,為Flask程序添加了一個命令行解析器。
Flask-Script自帶了一組常用選項,而且還支持自定義命令。
Flask-Script擴展使用pip安裝:

pip install flask-script

Flask-Script的使用前置步驟

這個實例顯示了把命令行解析功能添加到app程序中需要修改的地方。

from flask_script import Manager  # 注意原書中是flask.ext.script,這種方式現(xiàn)在已經(jīng)不推薦了
manager = Manager(app)
 
# ...
 
if __name__ == '__main__':
    manager.run()

這個擴展的初始化方法也使用于其他很多擴展:
把程序?qū)嵗鳛閰?shù)傳給構(gòu)造函數(shù),初始化主類的實例。
創(chuàng)建的對象可以在各個擴展中使用。
在這里,服務器由manager.run()啟動,啟動后就能解析命令行了。

使用Flask-Script命令行

現(xiàn)在我們像以往那樣,在命令行執(zhí)行
$ python hello.py
這次有點不一樣,并沒有直接運行服務器,而是出現(xiàn)了類似下面的消息:

usage: app.py [-?] {runserver,shell} ...
   
positional arguments:
    {runserver,shell}
        runserver         運行Flask開發(fā)服務器,例如 app.run()
        shell            在Flask app的上下文中運行python shell
optional arguments:
    -?, --help         顯示幫助信息并退出

也就是說,在python hello.py 后面必須跟著shell或者runserver兩者之一。
shell 命令用于在程序的上下文中啟動 Python shell 會話。
你可以使用這個會話中運行維護任務或測試,還可調(diào)試異常。

runserver 命令用來啟動 Web 服務器。
運行 python hello.py runserver 將以調(diào)試模式啟動 Web服務器,但是我們還有很多選項可用

runserver的幾個參數(shù)

  • -h HOST 設定為0.0.0.0表示為公網(wǎng),127.0.0.1表示為本局域網(wǎng)
  • -p 設定端口 Flask默認為5000,HTTP協(xié)議默認為80
  • -d 開啟調(diào)試模式
  • -D 不開啟調(diào)試模式
  • -r 自動重載文件
  • -R 不自動重載文件
  • 還有--threaded, --processes, --passthrough等選項。

例如要在服務器上運行Flask程序,應該這樣:

$ python hello.py runserver -h 0.0.0.0 -p 80
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內(nèi)容