Python框架學習之Flask中的視圖及路由

Python框架學習之Flask中的視圖及路由

  在前面一講中我們學習如何創建一個簡單的Flask項目,並做了一些簡單的分析。接下來在這一節中就主要來講講Flask中最核心的內容之一:Werkzeug工具箱。Werkzeug是一個遵循WSGI協議的Python函數庫。WSGI協議在前面的文章中也有提到(點我查看)。那Werkzeug有什麼作用呢?它其實實現了很多底層的東西,如Request、Response和集成URL請求路由等。

 

一、Werkzeug的組成:

  

 

二、routing模塊

  routing模塊的主要目的是負責實現URL解析。不同的URL能夠對應不同的視圖,從而得到不同的響應信息。

  1.Rule類:class Rule(RuleFactory):

    用來構造不同的url模式的對象。

1 if not string.startswith('/'):
2   raise ValueError('urls must start with a leading slash')

    這個判斷語句是Rule中的,表示url必須是以"/"開頭的字符串!

    

 

  2.Map類:

    用來存儲所有的URL規則和一些配置參數。

    

  3.MapAdapter類

    負責讓url與視圖建立關聯。

  

  4.BaseConverter

    這是一個轉換器基類,Flask中6個自帶的轉換器都是繼承於它!當然了,如果我們想要自定義一個路由匹配規則的話,也需要通過繼承它來實現。如自定義一個正則路由匹配。

    流程:

      (1). 導入BaseConverter類。在Flask中,所有 的路由的匹配規則都是使用轉換器對象進行記錄的。

      (2). 自定義轉換器。

      (3). 把自定義轉換器添加到默認轉換器的字典當中去。

      (4). 使用自定義轉換器實現自定義匹配規則。

    

複製代碼
from flask import Flask
from werkzeug.routing import BaseConverter

app = Flask(__name__)


class RegexConverter(BaseConverter):
    """自定義一個正則轉換器"""
    def __init__(self, map, *args):
        super(RegexConverter, self).__init__(map)

        # 將url中第一個參數當做匹配規則進行保存
        self.regex = args[0]
        print(map)
        print(args[0])


# 把自定義轉換器添加到默認轉換器的字典中,並將轉換器命名爲re
app.url_map.converters['re'] = RegexConverter
# print(app.url_map.converters)


# 定義一個正則的路由規則,匹配3個數字
@app.route('/regex/<re("[0-9]{3}"):u_id>')
def index(u_id):
    return "user_id爲%s" % u_id


if __name__ == "__main__":
    print(app.url_map)
    app.run(debug=True)
複製代碼

 

三、Request對象

  Request是Flask中表示當前請求的request對象,一般稱之爲請求上下文變量(可以理解成全局變量,在任意一個視圖中都可以訪問到)。常用的屬性有:

  args:url中的查詢字符串。本質上是鍵值對,跟在"?"後面,多個鍵值對之間使用"&"連接;

  form:請求url中的表單數據。也是由鍵值對組成,一般使用post方法提交數據

  cookies:請求中的cookie信息。由服務器生成的鍵值對,把值發送給客戶端並保存,稍後重點講解!

  files:上傳的文件

  

複製代碼
 1 from flask import Flask, request
 2 
 3 
 4 app = Flask(__name__)
 5 
 6 
 7 # 127.0.0.1:5000/?a=4&b=5
 8 @app.route('/')
 9 def index():
10     a = request.args.get('a')
11     b = request.args.get('b')
12 
13     print('a:%s, b:%s' % (a, b))
14     return '請求成功!!'
15 
16 
17 if __name__ == "__main__":
18     print(app.url_map)
19     app.run(debug=True)
複製代碼

 

四、狀態保持

  在分析Request對象的時候提到過Cookie,什麼是Cookie?Cookie有什麼用?以及如何通過Cookie及Session來實現狀態保持呢?

  (1). 爲什麼要有狀態保持的功能?

  因爲HTTP是一種無狀態協議,也就是說當用戶每一次請求時,都是一個新的請求,服務器根本不知道這個用戶做過什麼。比如當你在某個網站上想要買個東西,但是你每做一步都需要進行登錄直到下單成功,這樣對用戶來說就顯得特別麻煩,用戶體驗就特別差。如果我們的網站可以記錄該用戶的一些信息,那麼用戶就不需要每次都進行登錄了,用戶體驗就大大提高了。

  (2).Cookie是什麼?

  Cookie是由鍵值對組成的字符串,爲了辨別用戶身份,進行會話跟蹤而保存在本地的數據。

  Cookie是服務器生成的,發送給客戶端瀏覽器,瀏覽器將以鍵值對的形式保存着,當下一次請求同一網站的時候會攜帶着Cookie一起。

  有了Cookie我們就可以在很多地方看到一些似曾相識的廣告了!比如當你在某寶上買了什麼玩意,然後系統會推薦很多很多的相似的東西好讓你剁手!

  Cookie是基於域名安全的,不同域名的Cookie是不能相互訪問的。這就牽扯到CSRF了,這個留在模板中來說。

  

複製代碼
 1 from flask import Flask, request, make_response
 2 
 3 app = Flask(__name__)
 4 
 5 
 6 @app.route('/set_cookie')
 7 def set_cookie():
 8     # make_response()用來生成一些響應頭信息
 9     # 參數作爲響應體
10     resp_header = make_response('用來生成響應頭信息')
11     # 設置cookie,key爲unmae, value爲python, 有效期爲1分鐘
12     resp_header.set_cookie('uname', 'python', max_age=60)
13     return resp_header
14 
15 
16 @app.route('/get_cookie')
17 def get_cookie():
18     name = request.cookies.get('uname',"沒有獲取到有效的cookie")
19     return name
20 
21 
22 if __name__ == "__main__":
23     print(app.url_map)
24     app.run(debug=True)
複製代碼

  (3). session是什麼?

  在做Cookie的實驗中,我們發現Cookie保存的信息是明文形式,這樣是很不安全的。而且又是保存在本地的,不是保存在服務器上面。這樣的話,我們一些很重要的私人信息是會很容易被盜取。那有沒有一種保存在服務器的祕鑰,而且又是被加密的,返回給瀏覽器的只是一個key呢?

  那麼session就是這樣的,保存在服務器,而且是加密的,不容易被盜取。但是Session是依賴於Cookie的。

  session在Flask中是一種請求上下文對象,用於處理HTTP請求中的一些數據。

  如果要設置Session,那麼必須要設置SECRET_KEY變量。SECRET_KEY 的作用主要是提供一個值做各種 HASH,可在 Flask 和多個第三方擴展中使用。

  在上面提到過,一些配置信息最好不要和業務邏輯混合在一起。要麼單獨存放在一個文件中,如settings.py,要麼存放在一個ini文件中,或者添加到系統環境變量裏。這麼做的好處是如果你不把這些文件暴露出去,那麼其他人就很難看到!在Flask中都有提供這些操作接口(app.config.from_xxx()),很方便

  

複製代碼
 1 from flask import Flask, session
 2 
 3 # 自定義的配置文件,爲了安全起見,裏面可以做一些數據庫連接、祕鑰設置...
 4 from settings import MyConfig
 5 
 6 app = Flask(__name__)
 7 
 8 # 從.py的配置文件中加載一些配置變量,如DEBUG, SECRET_KEY,...
 9 app.config.from_object(MyConfig)
10 
11 
12 @app.route('/session')
13 def set_session():
14     session['name'] = 'python'
15     return '設置session成功'
16 
17 
18 if __name__ == "__main__":
19     print(app.url_map)
20     app.run()
複製代碼

 

五、請求鉤子

  在Flask中有一個請求鉤子,就是4個裝飾器。但是在其他框架中,如Django、Scrapy中被稱爲中間件,所以也可以把請求鉤子稱作是中間件!這其實是一種編程思想(AOP切面編程)的體現。對AOP編程感興趣的讀者可以自行搜索瞭解一下!這裏主要講講Flask中的請求鉤子。

  Flask中的請求鉤子分別是:before_first_request、before_request、after_request、teardown_request。這些請求鉤子有什麼作用呢?可以把他們想象成C++/Java中的構造函數和析構函數,即做一些初始化和銷燬的工作!其中最主要的功能還是在請求結束時,指定數據的交互格式,如指定Json格式。

  [email protected]_first_request:在處理第一個請求前被執行,而且只會執行一次。

  [email protected]_request:每次請求前被執行,可以做一些預檢工作,如果不滿足某些條件就return,然後視圖就不會被執行了

  [email protected]_request:在每個視圖執行完畢之後並且沒有錯誤時調用,可以設置一些響應頭信息,等等操作。必須返回response

  [email protected]_request:每次請求後被調用,接受一個參數:錯誤信息。

  

複製代碼
 1 from flask import Flask, request, abort
 2 
 3 from settings import MyConfig
 4 
 5 app = Flask(__name__)
 6 
 7 # 配置信息
 8 app.config.from_object(MyConfig)
 9 
10 
11 # 第一次請求前被調用,相當於__init__方法
12 @app.before_first_request
13 def before_first_request():
14     print('我只會被調用一次哦!')
15 
16 
17 # 在每次請求前被調用,可以做一些請求檢驗
18 # 如果請求的檢驗不成功,可以直接在此方法中進行響應,直接return後,不在繼續往下執行
19 @app.before_request
20 def before_request():
21     print(request.args.get('wd', '沒有找到查詢參數'))
22     if "?" not in request.url:
23         # 這個return 語句返回個客戶端瀏覽器,並作爲響應體
24         return 'url中沒有查詢參數'
25     print('你的請求URL:%s' % request.url)
26     # abort(500)
27 
28 
29 # 執行完視圖函數之後被調用,並且會把視圖函數生成的響應傳入,可以對response做一些設置
30 #
31 @app.after_request
32 def after_request(response):
33     # print(response.headers)
34 
35     # if response.headers.startswith('text'):
36     #     response.headers['Content-Type'] = 'application/json'
37     print('對響應信息做了一些更改!')
38     # 必須返回一個response
39     return response
40 
41 
42 # 在每次請求之後都會被調用,會接受一個參數,參數是服務器出現的錯誤信息
43 @app.teardown_request
44 def teardown_request(e):
45     print('teardown_request')
46     print(e)
47 
48 
49 @app.route('/args/<int:p1>')
50 def index1(p1):
51     return "接收到參數%s" % p1
52 
53 
54 @app.route('/args/<int:p2>')
55 def index2(p2):
56     return "接收到參數%s" % p2
57 
58 
59 if __name__ == '__main__':
60     app.run()
複製代碼

 

六、上下文對象

  1. 什麼是上下文?

    上下文可以當成一個容器,裏面保存着從開始到目前爲止發生的一些事情,就相當於一個日誌一樣。在Flask中,有兩種的上下文:請求上下文(request context)和應用上下文(application context)。

  2. 請求上下文:

    請求對象指每次發生HTTP請求時,在Flask對象內部創建的對象。

    請求上下文包括:request對象和session對象。

    request:主要保存着當前本次請求的相關數據,上文提到的那些常用屬性。針對的是HTTP請求。

    session:用來保存請求會話中的信息,主要是用戶信息。

  3.應用上下文:

    應用對象是當調用app=Flask(__name__)時創建的對象,主要是幫助request獲取當前的應用。

    應用上下文包括:current_app和g對象

    current_app:用於存儲程序中的變量,主要是做日誌使用,生命週期比request上下文長

    g:是一個臨時變量,保存的是當期那請求的全局變量,不同的請求會有不同的全部變量。

  4.區別:

    請求上下文主要是保存客戶端與服務器交互的數據;應用上下文是在程序運行過程中,保存着一些配置信息。

    一般應用上下文的生命週期長於請求上下的,但只是current_app。

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