實戰使用flask搭建web應用程序

本文小編將帶領大家詳細地瞭解Python中的flask框架,並且一步步演示具體如何搭建一個完整的web應用程序。

1、你將學到Flask應用程序的不同部分。同時,你將編寫和運行你的第一個Flask web應用程序

所有的Flask應用程序都必須創建一個應用程序實例 。使用web服務器網關接口協議將所有從客戶端接收的請求傳遞給這個對象處理。這個應用程序實例就是Flask類的一個對象,通常使用下面的方式創建:

from flask import Flask
app = Flask(__name__)

Flask類構造函數唯一需要的參數就是應用程序的主模塊或包。對於大多數應用程序,Python的__name__變量就是那個正確的、你需要傳遞的值。

注:對於Flask開發者來說,傳給Flask應用程序構造函數的name參數是比較容易弄混淆的。Flask使用這個參數來確定應用程序的根目錄,這樣以後可以相對這個路徑來找到資源文件。稍後你可以看到更復雜的應用程序實例初始化,但是對於簡單應用程序這些已經足夠了。在學習中有迷茫不知如何學習的朋友小編推薦一個學Python的學習q u n 315 -346- 913可以來了解一起進步一起學習!免費分享精品視頻資料

2、路由和視圖函數
客戶端例如web瀏覽器發送 請求 給web服務,進而將它們發送給Flask應用程序實例。應用程序實例需要知道對於各個URL請求需要運行哪些代碼,所以它給Python函數建立了一個URLs映射。這些在URL和函數之間建立聯繫的操作被稱之爲 路由 。

在Flask應程序中定義路由的最便捷的方式是通過顯示定義在應用程序實例之上的app.route裝飾器,註冊被裝飾的函數來作爲一個路由。下面的例子會演示怎樣使用裝飾器來申明一個路由:

@app.route('/')
def index():

return '<h1>Hello World!</h1>'

注**:裝飾器是Python語言的標準特性;它們可以以不同方式改變函數的行爲。一個常見的模式是使用裝飾器來註冊函數作爲一個事件處理程序。
在上一個示例給應用程序的根URL註冊index()函數作爲事件的處理程序。如果這個應用程序被部署在服務器上並綁定了 www.example.com 域名,然後在你的瀏覽器地址欄中輸入 http://www.example.com 將觸發index()來運行服務。客戶端接收到的這個函數的返回值被稱爲 響應 。如果客戶端是web瀏覽器,響應則是顯示給用戶的文檔。
**
**類似於index()的函數被稱作 視圖函數 。通過視圖返回的響應可以是簡單的HTML內容的字符串,但它也可以市更復雜的形式,正如您將看到的。

注:響應字符串嵌入在Python代碼中導致代碼難以掌控,在此只是介紹響應的概念。
如果你注意到你每天使用的一些網站URLs如何形成的,你將會發現很多都有變量。例如,你的Facebook個人信息頁的URL是 http://www.facebook.com/ ,所以你的用戶名是它的一部分。Flask在路由裝飾器中使用特殊的語法支持這些類型的URLs。下面的示例定義了一個擁有動態名稱組件的路由:
**
@app.route('/user/')
def user(name):

return '<h1>Hello, %s!</h1>' % name

用尖括號括起來的部分是動態的部分,所以任何URLs匹配到靜態部分都將映射到這個路由。當視圖函數被調用,Flask發送動態組件作爲一個參數。在前面的示例的視圖函數中,這個參數是用於生成一個個性的問候作爲響應。

在路由中動態組件默認爲字符串,但是可以定義爲其他類型。例如,路由/user/只匹配有一個整數在id動態段的URLs。Flask路由支持int、float和path。path同樣是字符串類型,但並不認爲斜槓是分隔符,而認爲它們是動態組件的一部分。

3、服務啓動
應用程序實例有一個run方法用於啓動Flask集成的web服務:

if name == '__main__':

app.run(debug=True)

name == '__main__'在此處使用是用於確保web服務已經啓動當腳本被立即執行。當腳本被另一個腳本導入,它被看做父腳本將啓動不同的服務,所以app.run()調用會被跳過。

一旦服務啓動,它將進入循環等待請求併爲之服務。這個循環持續到應用程序停止,例如通過按下Ctrl-C。

有幾個選項參數可以給app.run()配置web服務的操作模式。在開發期間,可以很方便的開啓debug模式,將激活 debugger 和 reloader 。這樣做是通過傳遞debug爲True來實現的。

4、一個完整的應用程序
整個 hello.py 應用程序腳本只不過將前面描述的三個部分結合在一個文件中。

示例 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)

建議:如果你有克隆在GitHub上的應用程序,你現在可以運行git checkout 2a來切換到這個版本的應用程序。
運行應用程序之前,請確保你在之前創建的虛擬環境已經是激活狀態且已安裝Flask。現在打開你的web瀏覽器並在地址欄輸入 http://127.0.0.1:5000/
然後輸入以下命令啓動應用程序:
(venv) $ python hello.py

  • Running on http://127.0.0.1:5000/
  • Restarting with reloader
    如果你輸入任何其他URL,應用程序將不知道如何操作它並且將返回錯誤代碼404給瀏覽器——當你訪問一個不存在的網頁也會得到該錯誤。

下面所示應用程序的增強版添加了第二個動態路由。當你訪問這個URI,你應該可以看到一個個性的問候。

示例hello.py:帶有動態路由的Flask應用程序

from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():

  return '<h1>Hello World!</h1>'

@app.route('/user/')
def user(name):

  return '<h1>Hello, %s!</h1>' % name

if name == '__main__':

  app.run(debug=True)

建議:如果你有克隆在GitHub上的應用程序,你現在可以運行git checkout 2b來切換到這個版本的應用程序。
測試動態路由,確保服務正在運行隨後訪問 http://localhost:5000/user/Dave 。生成的應用程序會使用動態參數名響應一個定製的問候。嘗試不同的名稱,看看視圖函數總是生成響應基於給定的名稱。

5、請求-響應循環
現在你已經玩過一個基本的Flask應用程序,你也許想要知道更多關於Flask如何施展魔力。下面章節描述了一些框架設計方面的特點。

5.1、應用程序Context和請求Context

當Flask從客戶端收到一個請求,它需要提供幾個可用對象給視圖函數處理。request對象是個不錯的例子,它封裝了客戶端發送的HTTP請求。

Flask視圖函數訪問request對象的最好方式,就是作爲一個參數發送它,但這需要每個單一視圖函數在應用程序中有一個額外的參數。考慮一下,如果request對象不是唯一一個視圖函數需要訪問完成請求的對象,事情將會變得更加複雜。

爲了避免弄亂視圖函數那些可能需要或不需要的參數,Flask使用context來臨時確定可訪問的全局對象。也多虧了context,視圖函數可以寫成下面這樣:

from flask import request
@app.route('/')
def index():

  user_agent = request.headers.get('User-Agent')
  return '<p>Your browser is %s</p>' % user_agent

注意,在這個視圖函數中,request是如何被作爲一個全局變量來使用的。現實中,request是不能作爲全局變量的,如果是多線程服務器,同一時間線程作用於不同客戶端的不同請求,所以每一個線程需要看到request中的不同對象。contexts使得Flask確定可訪問的全局變量而不干擾其他線程。

注:線程是可以獨立管理的最小指令序列。一個進程中有多個活動的線程是非常常見的,有時分享內存或文件句柄資源。多線程web服務器會啓動一個線程池並從池中選擇一個線程來處理每個傳入的請求。
Flask有兩類context:應用級context 和 請求級context。
Flask激活(或壓棧)應用級context和請求級context在調度請求之前,然後刪除他們當請求被處理後。當應用程序context被壓入棧,線程中current_app和g變量變得可用;同樣的,當請求級context被壓入棧,request和session變量也同樣變得可用。如果這些變量中的任何一個不是由激活的應用級或請求級context訪問,會產生錯誤。
下面的Python shell會話演示了應用級context是如何工作的:

from hello import app
from flask import current_app
current_app.name
Traceback (most recent call last):

...
RuntimeError: working outside of the application context

app_ctx = app.app_context()
app_ctx.push()
current_app.name

'hello'

app_ctx.pop()

在這個示例中,當應用級context沒有激活,但是卻作爲有效的context被壓入棧中,current_app.name報錯。可以看到在應用程序實例中一個應用級context是如何通過調用app.app_context()來獲得的。

**5.2、請求調度
**
當一個應用程序收到客戶端的請求,它需要找到響應的視圖函數爲之服務。對於這個任務,Flask會在應用程序的URL映射中查找請求的URL,該映射包含URLs和操作它們的視圖函數。Flask通過app.route裝飾器或非裝飾器版本app.add_url_rule()來建立這個映射。

看一下Flask應用程序中URL映射是怎樣的,你可以在Python shell中檢查hello.py創建的映射。測試中,請確保你的虛擬環境是激活狀態:
(venv) % python

from hello import app
app.url_map

Map([ index>,
' (HEAD, OPTIONS, GET) -> static>,
' (HEAD, OPTIONS, GET) -> user>])
/和/user/路由是由應用程序中的app.route所定義。/static/路由是由Flask添加,用於訪問靜態文件的一個特殊路由。
URL映射中所示的HEAD、OPTIONS、GET元素爲request方法,由路由處理。Flask連接方法到每個路由,這樣不同的請求方法發送到相同的URL可以被不同的視圖函數處理。HEAD和OPTIONS方法由Flask自動管理,所以實際上可以說,在這個應用程序中URL映射的三個路由都連接到GET方法了。
5.3、請求Hooks

有些時候在每個請求處理之前或之後執行代碼是非常有用的。例如,在開始每一個請求前可能有必要創建數據庫連接,或對用戶請求進行驗證。爲了避免複製處理這些操作的代碼到每一個視圖函數中,Flask給你選擇註冊相同函數來調用,在請求被分配給視圖函數之前或之後。

請求hooks由裝飾器實現。下面是四個Flask支持的hooks:

(1)before_first_request:在第一個請求被處理前註冊一個函數運行。
(2)before_request:在每一個請求前註冊一個函數運行。
(3)after_request:如果沒有未處理的異常發生,在每一個請求後註冊一個函數運行。
(4)teardown_request:即使未處理的異常發生,在每一個請求後註冊一個函數運行。
在請求hook函數和視圖函數之間共享數據的慣用方法就是使用g全局context。例如,before_request處理程序可以從數據庫加載已登錄的用戶並保存在g.user中。之後,當視圖函數被調用,可以從那訪問用戶。

5.4、響應

當Flask調用一個視圖函數,並期望它的返回值去響應該請求。大多數的響應是將簡單字符串構成的HTML頁面發回給客戶端。

但是HTTP協議需要比字符串更多的信息作爲請求的響應。一個HTTP響應中非常重要的部分是狀態碼,Flask默認設置200來指示請求已經成功處理。

當視圖函數需要用不同的狀態碼響應,可以在響應文本後添加數字碼作爲第二個返回值。例如,下面的視圖函數返回400錯誤狀態碼的請求:

@app.route('/')
def index():

  return '<h1>Bad Request</h1>', 400

視圖函數返回的響應還可以攜帶第三個參數,添加一個頭部字典給HTTP響應。
除了返回一個、兩個或三個值的元組,Flask視圖函數可以選擇返回response對象。make_response()函數可攜帶一個、兩個或三個參數,和視圖函數返回的值一樣,並返回一個response對象。有時候在視圖函數中執行這個轉換是非常有用的,然後使用response對象中的方法進一步配置響應。下面的示例創建response對象並設置cookie:
from flask import make_response
@app.route('/')
def index():

  response = make_response('<h1>This document carries a cookie!</h1>')
  response.set_cookie('answer', '42')
  return response

有一類特殊的響應稱作重定向。這類響應不包含頁面文檔;只是給瀏覽器一個新的URL去加載新的頁面。重定向通常和web表單一起使用。

重定向通常由302響應狀態碼註明並且重定向的URL由頭部的Location給出。重定向響應可以使用三個值的返回生成,也可通過響應對象生成,但是鑑於它頻繁的使用,Flask提供redirect()函數來創建這樣的響應:

from flask import redirect

@app.route('/')
def index():

  return redirect('http://www.example.com')

另一個具有中斷功能的特殊響應用來錯誤處理。下面的示例,當URL給出的id動態參數不是一個合法的用戶時返回狀態碼404:

from flask import abort

@app.route('/user/')
def get_user(id):

  user = load_user(id)
  if not user:
       abort(404)
  return '<h1>Hello, %s</h1>' % user.name

注意終止不是指將控制權返回給調用它的函數,而是指通過拋出異常將控制權返回給web服務。

6、Flask擴展
Flask是可擴展的。它故意騰出地給重要的功能,例如數據庫和用戶授權,給你自由去選擇最適合你的應用程序的包,或寫一個自己想要的。

社區開發了非常多的擴展用於各種用途,如果這還不夠,可以使用任何Python標準包和庫。
**6.1、Flask-Script命令行選項
**
Flask開發,其web服務器支持一系列的啓動配置選項,但是配置它們的唯一方式只有在腳本中傳遞參數給app.run()並調用。這不是非常的方便,理想方法是通過命令行參數傳遞配置選項。

Flask-Script是給你的Flask應用程序添加命令行解釋的擴展。它打包了一組通用的選項,還支持自定義命令。

使用pip安裝擴展:

(venv) $ pip install flask-script

下面展示了在 hello.py 應用程序中添加命令行解釋的變化。
示例. hello.py:使用Flask-Script

from flask.ext.script import Manager
manager = Manager(app)
if name == '__main__':

 manager.run()

專爲Flask開發的擴展暴露在flask.ext命名空間下。Flask-Script從flask.ext.script中導出一個名爲Manager的類。

初始化這個擴展的方法和其他許多擴展一樣:主類實例的初始化是通過將應用程序實例作爲參數傳遞給構造函數實現的。創建的對象適當的用於每一個擴展。在這個示例中,服務器啓動通過manager.run()來路由,且命令行在這被解析。

建議:如果你有克隆在GitHub上的應用程序,你現在可以運行git checkout 2c來切換到這個版本的應用程序。 因爲這些變化,應用程序獲得一組基本的命令行選項。運行hello.py顯示可用信息:
$ python hello.py
usage: hello.py [-h] {shell, runserver} ...
positional arguments:{shell, runserver}
shell 在Flask應用程序上下文的內部運行一個Python Shell。
runserver 運行Flask開發服務器,例如:app.run()
optional arguments:
-h, --help 顯示這個幫助信息並退出
shell命令用於在應用程序上下文中啓動一個Python shell會話。你可以使用這個會話去運行維護任務,或測試,或調試錯誤。
runserver命令,就像它的名稱一樣,啓動web服務。運行python hello.py runserver在調試模式下啓動web服務,還有更多的選項:
(venv) $ python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]

   [--processes PROCESSES] [--passthrough-errors] [-d]
   [-r]

運行Flask開發服務器,例如:app.run()
optional arguments:
-h, --help 顯示這個幫助信息並退出
-t HOST, --host HOST
-p PORT, --port PORT
--threaded
--processes PROCESSES
--passthrough-errors
-d, --no-debug
-r, --no-reload

--host參數是一個非常有用的選項,因爲它能告訴web服務器監聽哪個網絡接口的客戶端連接。默認,Flask開發的web服務器監聽localhost的連接,所以只有來自內部計算機運行的服務器可以接收。下面的命令使得web服務器監聽公網接口,其他網絡上的計算機可以連接

(venv) $ python hello.py runserver --host 0.0.0.0

現在web服務器應該可以從網絡中的任何一臺計算機訪問 http://a.b.c.d:5000 ,“a.b.c.d

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章