by 太陽雪
WEB 開發是現在程序必會的技能,因為大部分軟件都以 Web 形式提供,及時制作后台開發,或者只做前台開發,也需要了解 Web 開發的概念和特點。
由於 Python 是解釋性腳本語言,用來做 Web 開發非常適合,而且 Python 有上百中 Web 開發框架,以及成熟的模板技術,使得Web開發如虎添翼。今天借用 Flask 框架,快速學習一下 Python 的 Web 開發知識。
Flask 框架
Flask 的設計易於使用和擴展。它的初衷是為各種復雜的Web應用程序構建堅實的基礎。可以自由地插入任何擴展。也可以自由構建自己的模塊。Flask 適合各種項目。它對原型設計特別有用。Flask 依賴於兩個外部庫:Jinja2 模板引擎和 Werkzeug WSGI 工具包。
Flask 是最精致,功能最豐富的微框架之一。Flask 還很年輕,擁有蓬勃發展的社區,一流的擴展和漂亮的 API。Flask 具有快速模板,強大的 WSGI 功能,在 Web 應用程序和庫級別的完整單元可測性,以及大量文檔等優點。
選用 Flask 框架也是因為它方便入手,結構簡單,零配置,是個學習 Python Web 開發的好工具。
安裝 Flask
像其他模塊一樣,Flask 的安裝很簡單,下面通過 pip 包管理器來安裝
pip install flask
檢查一下是否安裝正確,在命令行下輸入 python
進入命令行模式,
引入 flask
模塊,回車
>>> import flask
>>>
如果沒有錯誤提醒,就說明安裝成功了
Hello world
下面寫個最簡單的Web應用 hello.py
from flask import Flask # 引入Flask模塊
app = Flask(__name__) # 創建一個應用
@app.route('/')
def index(): # 定義根目錄處理器
return '<h1>Hello World!</h1>'
if __name__ == '__main__':
app.run() # 啟動服務
打開終端,跳轉到 hello.py
文件所在的文件夾,進入 python 命令行模式,啟動服務
>>> python hello.py
如果一起正常的話會有類似下面的反饋
* Serving Flask app "hello" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
因為是通過
app.run()
啟動的服務,所以會有個錯誤提示,提醒不能將此Web應用部署在生產環境中,可以暫時忽略
此時,打開瀏覽器,輸入127.0.0.1:5000/ 或者 localhost:5000/, 就可以看到 Hello World! 歡迎字樣。
路由
路由是 Web 開發中一個很重要的概念,用來將不同的請求,映射到響應的處理方法上,這個方法被稱為視圖函數。比如剛才的 Hello
應用,將根請求,映射到index
處理方法上,下面簡單了解下Flask對路由的支持
Flask通過修飾器(和Java的注解類似)來建立路由映射關系的,已經看到修飾器是 app.rotue()
簡單路由
如 訪問 /hello
@app.route('/hello')
def hello():
return 'Hello!'
動態路由
如訪問 /user/bob
或者 /user/lily
都會映射到同一視圖函數上
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s! </h1>' % name
動態域名中動態的部分可以作為視圖函數的參數,也支持多個動態參數,如訪問 /user/bob/23
@app.route('/user/<name>/<age>')
def user(name, age):
return "<h1> Hello, %s, you're %s years old" % (name, age)
還可以指定動態部分的數據類型,如
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return 'Subpath %s' % escape(subpath)
支持的數據類型
類型 | 說明 |
---|---|
string | (默認值) 任何不包含斜杠的文本 |
int | 正整數 |
float | 正浮點數 |
path | 類似 string ,但可以包含斜杠 |
uuid | 接受 UUID 字符串 |
指定HTTP 方法
HTTP 協議,支持多種 HTTP 方法,例如 HEAD
、OPTIONS
,以及常用的 GET
、POST
等,Flask自動處理了 HEAD
和 OPTIONS
,路由默認接受的方法是 GET,如果要匹配其他請求方法,可以在路由方法的 methods
參數來指定
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
復合路由
也可以將多個路由規則,用於一個視圖函數, 如訪問 /job/
和訪問 /work/
效果是一樣的
@app.route('/job/')
@app.route('/work/')
def show_works():
return 'This is works page'
再復雜一點的例子
@app.route('/users/', defaults={'page': 1})
@app.route('/users/page/<int:page>')
def show_users(page):
pass
上面的代碼表示,當訪問 /user/
或者 /user/page/<pageindex>
時,都會有 show_users
視圖函數來處理, 而且還為 /user/
提供了默認值,即訪問 /user/
相當於訪問 /user/page/1
請求和響應
Web 應用,最重要的事情就是處理接收到的請求,並返回響應。Flask 框架也一樣,它提供了請求對象 request
和響應對象 response
,可以方便的在視圖函數中使用。
請求
Flask 將客戶端發送的 HTTP 請求封裝成了 request
請求對象,並且使用上下文 (context) 臨時將 request
變為全局可訪問的,於是在視圖還是中,就可以直接使用了。
注意:
request
並非真正的全局變量!試想,在多線程服務器中,多個線程同時處理不同客戶端發送的不同請求時,每個線程看到的request
對象必然不同。Falsk 使用上下文讓特定的變量在一個線程中全局可訪問,與此同時卻不會干擾其他線程。
Flask 有兩種上下文,分別為程序上下文和請求上下文,各自對應的全局變量如下表:
變量名 | 上下文類型 | 備注 |
---|---|---|
current_app | 程序上下文 | 表示當前運行的程序實例 |
g | 程序上下文 | 處理請求時用作臨時存儲對象,每次請求都會重新設值 |
request | 請求上下文 | 客戶端發來的request請求對象 |
session | 請求上下文 | 請求攜帶的會話信息 |
使用request
對象前,需要先引入
from flash import request
request
對象提供了豐富的屬性和方法,這里舉個例子:
通過使用 method
屬性可以操作當前請求方法,通過使用 form
屬性處理表單數據(在 POST
或者 PUT
請求 中傳輸的數據)。以下是使用上述兩個屬性的例子:
@app.route('/login', methods=['POST', 'GET'])
def login():
error = None
if request.method == 'POST':
if valid_login(request.form['username'],
request.form['password']):
return log_the_user_in(request.form['username'])
else:
error = 'Invalid username/password'
# the code below is executed if the request method
# was GET or the credentials were invalid
return render_template('login.html', error=error)
注意:當 form 屬性中不存在這個鍵時會發生什么?會引發一個 KeyError 。 如果不處理這個錯誤 ,就會顯示一個 HTTP 400 Bad Request 錯誤頁面。
如果要操作 URL (如 ?key=value )中提交的參數可以使用 args 屬性,如 : searchword = request.args.get('key', '')
請求鈎子
有時在處理請求之前或之后執行代碼會很有用。例如,在請求開始時,可能需要創建數據庫連接或者認證發起請求的用戶。為了避免在每個視圖函數中都使用重復的代碼,Flask 提供了注冊通用函數的功能,注冊的函數可在請求被分發到視圖函數之前或之后調用。
請求鈎子使用修飾器實現。Flask 支持以下4種鈎子:
before_first_request
:注冊一個函數,在處理第一個請求之前運行。before_request
:注冊一個函數,在每次請求之前運行。after_request
:注冊一個函數,如果沒有未處理的異常拋出,在每次請求之后運行。teardown_request
:注冊一個函數,即使有未處理的異常拋出,也在每次請求之后運行。
示例:
在接受到第一個請求是,打印一句話:
@app.before_first_request
def first_quest():
print("run before first request")
在請求鈎子函數和視圖函數之間共享數據一般使用上下文全局變量g。
例如,before_request 處理程序可以從數據庫中加載已登錄用戶,並將其保存到 g.user 中。隨后調用視圖函數時,視圖函數再使用 g.user 獲取用戶。
響應
響應是 Web 服務器對請求的一個回應,在 Flask 中,有多種形式的響應。視圖函數的返回值會自動轉換為一個響應對象。
如果返回值是一個字符串,那么會被 轉換為一個包含作為響應體的字符串、一個 200 OK 出錯代碼 和一個 text/html
類型的響應對象。
如果返回值是一個字典,那么會調用 jsonify()
來產生一個響應。
以下是轉換的規則:
- 如果視圖返回的是一個響應對象,那么就直接返回它。
- 如果返回的是一個字符串,那么根據這個字符串和缺省參數生成一個用於返回的 響應對象。
- 如果返回的是一個字典,那么調用
jsonify
創建一個響應對象。 - 如果返回的是一個元組,那么元組中的項目可以提供額外的信息。元組中必須至少 包含一個項目,且項目應當由
(response, status)
、(response, headers)
或者(response, status, headers)
組成。status
的值會重載狀態代碼,headers
是一個由額外頭部值組成的列表 或字典。 - 如果以上都不是,那么 Flask 會假定返回值是一個有效的 WSGI 應用並把它轉換為 一個響應對象。
除此之外,還可以通過 make_response()
函數,創建可以響應對象,做更個性的事情。
使用make_response()
前,需要先引入
from flask import make_response
示例:
- 響應有元組構成
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
@app.errorhandler 修飾符,會將一個響應代碼映射到一個視圖函數上,這里是將404(找不到頁面)碼,處理成一個個性的錯誤頁面
另外,
render_template
是 Flask 的模板函數,簡單理解就是格式化一個動態的 html 字符串,關於模板的詳細用法,會在模板章節描述
- 使用 make_response() 包裹返回表達式,獲得響應對象,並對該對象 進行修改,然后再返回:
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
總結
本文借助 Flask 框架,簡要介紹了下 Python Web 開發的基本知識和技術,希望能幫助您快速入門,在 Python 學習的道路上走的更順暢。后續還會將就 Web 開發的話題,對模板、數據庫 以及擴展功能等進行講解,敬請期待!
參考
- 圖書: Flask Web開發
- Flask快速上手: https://dormousehole.readthedocs.io/en/latest/quickstart.html
- Flask入門到精通(二): https://www.cnblogs.com/java-wgm/p/6602900.html
- Web服務器網關接口
關注公眾號:python技術,回復"python"一起學習交流