在開始之前,說點提外話,隨著對Pylons了解的深入,你可能時不時需要看看相關(guān)組件/軟件包是否有更新出來,方法也不復(fù)雜,通過"easy_install -U [組件名]"即可,在學(xué)習(xí)或者是開發(fā)過程中,最好是保持環(huán)境相對較新,直到出現(xiàn)相對大的release或者即將進入產(chǎn)品部署階段。
繼續(xù)介紹Pylons組件,先看個例子。首先用"paster controller hello"增加一個controller,路徑中會增加出以下兩個文件:
controllers/hello.py
tests/functional/test_hello.py
分別對應(yīng)新增的controller類HelloController和功能測試類TestHelloController,它們分別繼承自WSGIController->BaseController和TestCase->TestController。
我們主要看hello.py,默認內(nèi)容如下:
?1?import?logging
?2?
?3?from?pylons?import?request,?response,?session,?tmpl_context?as?c
?4?from?pylons.controllers.util?import?abort,?redirect_to
?5?
?6?from?newapp.lib.base?import?BaseController,?render
?7?#from?newapp?import?model
?8?
?9?log?=?logging.getLogger(__name__)
10?
11?class?HelloController(BaseController):
12?
13?????def?index(self):
14?????????#?Return?a?rendered?template
15?????????#???return?render('/template.mako')
16?????????#?or,?Return?a?response
17?????????return?'Hello?World'
如果你的服務(wù)器沒有Ctrl-C停掉,那么這個時候你已經(jīng)可以通過
http://127.0.0.1:5000/hello/index看到該controller的處理結(jié)果了(Hello World)。
簡單改造一下17行:
????????from?pylons?import?config
????????return?'<br/>'.join(config.keys())
我們就可以在返回頁面上顯示出所有可以通過pylons.config訪問到的參數(shù)列表。出了返回文本,也可以通過render()方法交給頁面模板引擎生成頁面,也可以通過redirect_to()跳轉(zhuǎn)到其他URL。
Pylons是如何找到該請求應(yīng)該由HelloController的index方法來處理的呢?這背后發(fā)生了什么?答案就是Routes。
Routes的作者是Ben Bangert,是Pylons框架三個主要作者/維護者之一,早期的版本主要是仿照Ruby on Rails的routes.rb開發(fā)的,有RoR經(jīng)驗的朋友可能一眼就能發(fā)現(xiàn)它們之間的相似之處。目前Routes的最新版是1.10.2。
Pylons應(yīng)用中,routing的配置在config/routing.py,默認生成的內(nèi)容如下:
?1?"""Routes?configuration
?2?
?3?The?more?specific?and?detailed?routes?should?be?defined?first?so?they
?4?may?take?precedent?over?the?more?generic?routes.?For?more?information
?5?refer?to?the?routes?manual?at?http://routes.groovie.org/docs/
?6?"""
?7?from?pylons?import?config
?8?from?routes?import?Mapper
?9?
10?def?make_map():
11?????"""Create,?configure?and?return?the?routes?Mapper"""
12?????map?=?Mapper(directory=config['pylons.paths']['controllers'],
13??????????????????always_scan=config['debug'])
14?????map.minimization?=?False
15?????
16?????#?The?ErrorController?route?(handles?404/500?error?pages);?it?should
17?????#?likely?stay?at?the?top,?ensuring?it?can?always?be?resolved
18?????map.connect('/error/{action}',?controller='error')
19?????map.connect('/error/{action}/{id}',?controller='error')
20?
21?????#?CUSTOM?ROUTES?HERE
22?
23?????map.connect('/{controller}/{action}')
24?????map.connect('/{controller}/{action}/{id}')
25?
26?????return?map
在這個配置中,對我們剛才的實例起到?jīng)Q定性作用的是第23行,我們的輸入URL為"http://127.0.0.1:5000/hello/index",其中"/hello/index"通過"/{controller}/{action}"這個表達式match出controller為hello而action為index的解析結(jié)果,從而在controllers目錄找到hello.py,和其中HelloController的index方法,進行調(diào)用。
map.connect()在上面代碼中體現(xiàn)出兩種用法:
map.connect('pattern', key=value) - 指定默認的controller、action、id等
map.connect('pattern') - 直接指定pattern
pattern字符串允許通配符,通常在最后一個元素上,比如'/{controller}/{action}/{*url}',將后面的整個URL片段交給前面指定的controller/action處理。除此以外,map.connect()還支持
1- "路徑別名",如:
map.connect('name', 'pattern', [_static=True])
如果_static設(shè)為"True",表示為"靜態(tài)命名路徑"。
2- 額外的匹配條件,如:
map.connect('/{controller}/{action}/{id}', requirements={'year': '\d+',})
map.connect('/{controller}/{action}/{id}', conditions=dict(method=['GET','POST']))
所有的route優(yōu)先級為從上到下。Routes除了提供解析進來的URL的邏輯,在我們的controller和template代碼中,我們還可以方便的通過WebHelpers的url_for()方法計算相應(yīng)的URL。
Routes 1.x中的有一些仿routes.rb功能將會在2.0中被去掉,包括Route Minimization、Route Memory、Implicit Defaults等。如果有興趣的話,可以參考一下官方文檔,這里就不一一介紹了。為什么要去掉?當然主要的動機還是減少歧義,避免一些不必要的混淆。至于深層次的原因么,可以參考Tim Peters《The Zen of Python》中的一句經(jīng)典的Python哲學(xué):Explicit is better than implicit。什么?沒有聽說過?打開python命令行,輸入"import this"后回車,慢慢體會其中的道理吧。:)