當前位置:
首頁 > 最新 > Flask 應用中的 URL 處理

Flask 應用中的 URL 處理

來源:fanchunke1991

fanchunke.me/Flask/Flask應用中的URL處理/

在文章:《一個Flask應用運行過程剖析中》,在一個上下文環境中可以處理請求。如果不考慮在處理請求前後做的一些操作,Flask源碼中真正處理請求的是dispatch_request()方法。其源碼如下:

defdispatch_request(self):

"""Does the request dispatching. Matches the URL and returns the

return value of the view or error handler. This does not have to

be a response object. In order to convert the return value to a

proper response object, call :func:`make_response`.

"""

try:

endpoint,values=self.match_request()

returnself.view_functions[endpoint](**values)

exceptHTTPException,e:

handler=self.error_handlers.get(e.code)

ifhandlerisNone:

returne

returnhandler(e)

exceptException,e:

handler=self.error_handlers.get(500)

ifself.debugorhandlerisNone:

raise

returnhandler(e)

從上面的源碼中可以看到,dispatch_request()方法做了如下的工作:

對請求的URL進行匹配;

如果URL可以匹配,則返回相對應視圖函數的結果;

如果不可以匹配,則進行錯誤處理。

對於錯誤的處理,本文暫不做介紹。本文主要對Flask應用的URL模式以及請求處理過程中的URL匹配進行剖析。

Flask應用的url_map

Flask應用實例化的時候,會為應用增添一個url_map屬性。這個屬性是一個Map類,這個類在werkzeug.routing模塊中定義,其主要的功能是為了給應用增加一些URL規則,這些URL規則形成一個Map實例的過程中會生成對應的正則表達式,可以進行URL匹配。相關的概念和內容可以參考:《Werkzeug庫——routing模塊》。

在Flask源碼中,它通過兩個方法可以很方便地定製應用的URL。這兩個方法是:route裝飾器和add_url_rule方法。

1. add_url_rule

defadd_url_rule(self,rule,endpoint,**options):

options[ endpoint ]=endpoint

options.setdefault( methods ,( GET ,))

self.url_map.add(Rule(rule,**options))

add_url_rule方法很簡單,只要向其傳遞一條URL規則rule和一個endpoint即可。endpoint一般為和這條URL相關的視圖函數的名字,這樣處理就可以將URL和視圖函數關聯起來。除此之外,還可以傳遞一些關鍵字參數。調用該方法後,會調用Map實例的add方法,它會將URL規則添加進Map實例中。

2. route裝飾器

為了更加方便、優雅地寫應用的URL,Flask實現了一個route裝飾器。

defroute(self,rule,**options):

defdecorator(f):

self.add_url_rule(rule,f.__name__,**options)

self.view_functions[f.__name__]=f

returnf

returndecorator

route裝飾器會裝飾一個視圖函數。經route裝飾的視圖函數首先會調用add_url_rule方法,將裝飾器中的URL規則添加進Map實例中,視圖函數的名字會作為endpoint進行傳遞。然後在該應用的view_functions中增加endpoint和視圖函數的對應關係。這種對應關係可以在請求成功時方便地調用對應的視圖函數。

3. 一個簡單的例子

我們用一個簡單的例子來說明以上過程的實現:

>>>fromflaskimportFlask

>>>app=Flask(__name__)

>>>@app.route( / )

defindex():

return"Hello, World!"

>>>@app.route( / )

defuser(username):

return"Hello, %s"%username

>>>@app.route( /page/ )

defpage(id):

return"This is page %d"%id

以上代碼,我們創建了一個Flask應用app,並且通過route裝飾器的形式為app增加了3條URL規則。

首先: 我們看一下Flask應用的url_map長啥樣:

>>>url_map=app.url_map

>>>url_map

Map([index>,

static>,

page>,

user>

])

可以看到,url_map是一個Map實例,這個實例中包含4個Rule實例,分別對應4條URL規則,其中/static/在Flask應用實例化時會自動添加,其餘3條是用戶創建的。整個Map類便構成了Flask應用app的URL「地圖」,可以用作URL匹配的依據。

接下來: 我們看一下url_map中的一個屬性:_rules_by_endpoint:

>>>rules_by_endpoint=url_map._rules_by_endpoint

>>>rules_by_endpoint

{ index :[index>],

page :[page>],

static :[static>],

user :[user>]

}

可以看出,_rules_by_endpoint屬性是一個字典,反映了endpoint和URL規則的對應關係。由於用route裝飾器創建URL規則時,會將視圖函數的名字作為endpoint進行傳遞,所以以上字典的內容也反映了視圖函數和URL規則的對應關係。

再接下來: 我們看一下Flask應用的view_functions:

>>>view_functions=app.view_functions

>>>view_functions

{ index : ,

page : ,

user :

}

在用route裝飾器創建URL規則時,它還會做一件事情:self.view_functions[f.__name__] = f。這樣做是將函數名和視圖函數的對應關係放在Flask應用的view_functions。由於Map實例中存儲了函數名和URL規則的對應關係,這樣只要在匹配URL規則時,如果匹配成功,只要返回一個函數名,那麼便可以在view_functions中運行對應的視圖函數。

最後: 我們看一下URL如何和Map實例中的URL規則進行匹配。我們以/page/這條規則為例:

>>>rule=url_map._rules[2]

page>

>>>rule._regex

re.compile(ur ^\/page/(?Pd+)$ ,re.UNICODE)

>>>rule._regex.pattern

u ^\\/page\/(?P\d+)$

可以看到,在將一條URL規則的實例Rule添加進Map實例的時候,會為這個Rule生成一個正則表達式的屬性_regex。這樣當這個Flask應用處理請求時,實際上會將請求中的url和Flask應用中每一條URL規則的正則表達式進行匹配。如果匹配成功,則會返回endpoint和一些參數,返回的endpoint可以用來在view_functions找到對應的視圖函數,返回的參數可以傳遞給視圖函數。具體的過程就是:

try:

# match_request()可以進行URL匹配

endpoint,values=self.match_request()

returnself.view_functions[endpoint](**values)

...

看完本文有收穫?請轉發分享給更多人

關注「Python開發者」,提升Python技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python開發者 的精彩文章:

Python 中的作用域規則和閉包簡析
Python 源碼閱讀:int
Python 源碼閱讀: String
Python 中的屬性訪問與描述符
Python 源碼閱讀:對象

TAG:Python開發者 |