专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
51好读  ›  专栏  ›  Python开发者

Flask 应用中的 URL 处理

Python开发者  · 公众号  · Python  · 2017-10-07 20:43

正文

请到「今天看啥」查看全文


(点击 上方蓝字 ,快速关注我们)


来源:fanchunke1991

fanchunke.me/Flask/Flask应用中的URL处理/

如有好文章投稿,请点击 → 这里了解详情


在文章:《 一个Flask应用运行过程剖析中 》,在一个上下文环境中可以处理请求。如果不考虑在处理请求前后做的一些操作,Flask源码中真正处理请求的是dispatch_request()方法。其源码如下:


def dispatch_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 ()

return self . view_functions [ endpoint ]( ** values )

except HTTPException , e :

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

if handler is None :

return e

return handler ( e )

except Exception , e :

handler = self . error_handlers . get ( 500 )

if self . debug or handler is None :

raise

return handler ( e )


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


  1. 对请求的URL进行匹配;

  2. 如果URL可以匹配,则返回相对应视图函数的结果;

  3. 如果不可以匹配,则进行错误处理。


对于错误的处理,本文暂不做介绍。本文主要对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


def add_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装饰器。


def route ( self , rule , ** options ) :

def decorator ( f ) :

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

self . view_functions [ f . __name__ ] = f

return f

return decorator


route装饰器会装饰一个视图函数。经route装饰的视图函数首先会调用add_url_rule方法,将装饰器中的URL规则添加进Map实例中,视图函数的名字会作为endpoint进行传递。然后在该应用的view_functions中增加endpoint和视图函数的对应关系。这种对应关系可以在请求成功时方便地调用对应的视图函数。


3. 一个简单的例子


我们用一个简单的例子来说明以上过程的实现:


>>> from flask import Flask

>>> app = Flask ( __name__ )

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

def index () :

return "Hello, World!"

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

def user ( username ) :

return "Hello, %s" % username

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

def page ( id ) :

return "This is page %d" % id


以上代码,我们创建了一个Flask应用app,并且通过route装饰器的形式为app增加了3条URL规则。


首先 : 我们看一下Flask应用的url_map长啥样:


>>> url_map = app . url_map

>>> url_map

Map ([ < Rule '/' ( HEAD , GET ) -> index > ,

< Rule '/static/ ' -> static > ,

< Rule '/page/ ' ( HEAD , GET ) -> page > ,

< Rule '/ ' ( HEAD , GET ) -> 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' : [ < Rule '/' ( HEAD , GET ) -> index > ],

'page' : [ < Rule '/page/ ' ( HEAD , GET ) -> page > ],

'static' : [ < Rule '/static/ ' -> static > ],

'user' : [ < Rule '/ ' ( HEAD , GET ) -> user > ]

}


可以看出,_rules_by_endpoint属性是一个字典,反映了endpoint和URL规则的对应关系。由于用route装饰器创建URL规则时,会将视图函数的名字作为endpoint进行传递,所以以上字典的内容也反映了视图函数和URL规则的对应关系。


再接下来 : 我们看一下Flask应用的view_functions:


>>> view_functions = app . view_functions

>>> view_functions

{ 'index' : < function __main__ . index > ,

'page' : < function __main__ . page > ,

'user' : < function __main__ . 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 ]

>>> rule

< Rule '/page/ ' ( HEAD , GET ) -> page >

>>> rule . _regex

re . compile ( ur '^\|\/page\/(?P \d+)$' , 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 ()

return self . view_functions [ endpoint ]( ** values )

...


看完本文有收获?请转 发分享给更多人

关注「P ython开发者」,提升Python技能







请到「今天看啥」查看全文