- from routes import Mapper
- map = Mapper()
- map.connect('spch', '/blog', controller='main', action='index')
- result = map.match('/blog')
- print result
- {'action': u'index', 'controller': u'main'}
1.2 行创建一个mapper
3. 行注册一条路由, 路由名称为'spch', 路径为'/blog', controller为main,
action为index
可以这样认为,匹配到此条路由的请求交由controller处理,请求预调用的
函数为index
5. 创建好路由条目后,即可以进行匹配,调用match方法,匹配路径'blog'
6. 输出匹配结果
- map.connect(None, "/error/{action}/{id}", controller="error")
- result = map.match('/error/index/2')
- print result
- {'action': u'index', 'controller': u'error', 'id': u'2'}
1.注册了一条无名路由,并且action从匹配路由中获得
同样,我们可以省掉None
map.connect("/error/{action}/{id}", controller="error")
上述语句同样注册了一条无名路由。
Conditions
Conditions用于限制进行路由匹配,比如method
- m.connect("/user/list", controller="user", action="list", conditions=dict(method=["GET", "HEAD"]))
Requirements
有时只想匹配数字,或者匹配可选的几个条目
- map.connect(R"/blog/{id:\d+}")
- map.connect(R"/download/{platform:windows|mac}/{filename}")
\d表示匹配1位数字,\d+表示匹配多位
windows|mac 表示只匹配windows或者mac
可以将上述写成
- map.connect("/blog/{id}", requirements={"id": R"\d+"}
- map.connect("/download/{platform}/{filename}",
- requirements={"platform": R"windows|mac"})
Format extensions
通过{.format}来指定匹配格式
- map.connect('/entries/{id}{.format}')
- print map.match('/entries/2')
- {'id': u'2', 'format': None}
- print map.match('/entries/2.mp3')
- {'id': u'2', 'format': u'mp3'}
- map.connect('/entries/{id:\d+}{.format:mp3}')
- print map.match('/entries/2.mp3')
- {'id': u'2', 'format': u'mp3'}
- print map.match('/entries/2')
- {'id': u'2', 'format': None}
- print map.match('/entries/2.mp4')
- None
注意:{id:\d+}, 如果没有\d+, print map.match('/entries/2.mp4')将输出 {'id': u'2.mp4', 'format': None}是可以成功的。
有了\d+后,由于没有匹配format,同时\d+要求只匹配数字,所有2.mp4匹配失败
当路由条目过多时,需要一条一条注册,过于麻烦,此时可以通过resource route简化
- map.connect("messages", "/messages",
- controller="messages", action="create",
- conditions=dict(method=["POST"]))
- map.connect("messages", "/messages",
- controller="messages", action="index",
- conditions=dict(method=["GET"]))
- map.connect("formatted_messages", "/messages.{format}",
- controller="messages", action="index",
- conditions=dict(method=["GET"]))
- map.connect("new_message", "/messages/new",
- controller="messages", action="new",
- conditions=dict(method=["GET"]))
- map.connect("formatted_new_message", "/messages/new.{format}",
- controller="messages", action="new",
- conditions=dict(method=["GET"]))
- map.connect("/messages/{id}",
- controller="messages", action="update",
- conditions=dict(method=["PUT"]))
- map.connect("/messages/{id}",
- controller="messages", action="delete",
- conditions=dict(method=["DELETE"]))
- map.connect("edit_message", "/messages/{id}/edit",
- controller="messages", action="edit",
- conditions=dict(method=["GET"]))
- map.connect("formatted_edit_message", "/messages/{id}.{format}/edit",
- controller="messages", action="edit",
- conditions=dict(method=["GET"]))
- map.connect("message", "/messages/{id}",
- controller="messages", action="show",
- conditions=dict(method=["GET"]))
- map.connect("formatted_message", "/messages/{id}.{format}",
- controller="messages", action="show",
- conditions=dict(method=["GET"]))
上述路由条目可以使用这一条语句代替。
- map.resource("message", "messages")
函数原型:resource(member_name, collection_name, **kwargs)
- GET /messages => messages.index() => url("messages")
- POST /messages => messages.create() => url("messages")
- GET /messages/new => messages.new() => url("new_message")
- PUT /messages/1 => messages.update(id) => url("message", id=1)
- DELETE /messages/1 => messages.delete(id) => url("message", id=1)
- GET /messages/1 => messages.show(id) => url("message", id=1)
- GET /messages/1/edit => messages.edit(id) => url("edit_message", id=1)
这里有必要说一下member 路由与 collection路由。
上述的路由模型
- GET /messages => messages.index()
- POST /messages => messages.create()
- GET /messages/new => messages.new()
- PUT /messages/1 => messages.update(id)
- DELETE /messages/1 => messages.delete(id)
- GET /messages/1 => messages.show(id)
- GET /messages/1/edit => messages.edit(id)
1. 有的路由有id, 指向一个具体的对象
2. 有的路由没有id, 指向全体对象
3. 有的路由(index/create, show/update/delete)有相同的URL,但是HTTP method不同
4. 有的路由(show/edit)HTTP method和前缀相同,仅后缀不同
一个member路由指定具体实例,也就是说它们有id。而一个collection路由,
没有指定的实例,即没有给定id
综上:member路由操作一个单独的实例,而collection操作全体实例。
另一个函数collection也可以完成上述功能。
函数原型:collection(collection_name, resource_name, path_prefix=None, member_prefix='/{id}', controller=None, collection_actions=['index', 'create', 'new'],member_actions=['show', 'update', 'delete', 'edit'], member_options=None, **kwargs)
用法:
map.collection('entries', 'entry')
RoutesMiddleware将请求应声到相应WSGI程序,它将路由匹配结果存到environ环境变量中去。
- from routes.middleware import RoutesMiddleware
- app = RoutesMiddleware(wsgi_app, map) # ``map`` is a routes.Mapper.
map调用match匹配URL,并设置WSGI环境变量
- environ['wsgiorg.routing_args'] = ((url, match))
- environ['routes.route'] = route
- environ['routes.url'] = url
route为匹配到的路由,url为一个URLGenerator对象,match为匹配所得条目。
app为一个RoutesMiddleware对象,内部重载__call__(def __call__(self, environ, start_response))仍为一个wsgi应用。
wsgi_app为一个wsgi程序,RoutesMiddleware将环境变量(environ)设置好后,调用wsgi_app进行后续处理。
下面是一个实际的输出:
- wsgiorg.routing_args = (<routes.util.URLGenerator object at 0x0287AFB0>,
- {'action': u'index', 'controller': <__main__.Resourse instance at 0x02876E40>})
- routes.route = <routes.route.Route object at 0x02871F10>
- routes.url = <routes.util.URLGenerator object at 0x0287AFB0>
本文地址:http://blog.youkuaiyun.com/spch2008/article/details/9004926
1.下载库文件
webob库:http://download.youkuaiyun.com/detail/spch2008/5497755
routes库:http://download.youkuaiyun.com/detail/spch2008/5497757
repoze库:http://download.youkuaiyun.com/detail/spch2008/5499231
2. 组织代码
3. 代码
- '''''
- Created on 2013-6-1
- @author: spch2008
- '''
- from wsgiref.simple_server import make_server
- import routes.middleware
- import webob.dec
- import webob.exc
- class Controller:
- @webob.dec.wsgify
- def __call__(self, req):
- return webob.Response("Hello World!")
- class Router(object):
- def __init__(self):
- self._mapper = routes.Mapper()
- self._mapper.connect('/spch',
- controller=Controller(),
- action='index',
- conditions={'method': ['GET']})
- self._router = routes.middleware.RoutesMiddleware(self._dispatch, self._mapper)
- @webob.dec.wsgify
- def __call__(self, req):
- return self._router
- @staticmethod
- @webob.dec.wsgify
- def _dispatch(req):
- match = req.environ['wsgiorg.routing_args'][1]
- if not match:
- return webob.exc.HTTPNotFound()
- app = match['controller']
- return app
- app = Router()
- httpd = make_server('localhost', 8282, app)
- httpd.serve_forever()
22行:创建一个mapper
23行:#注册一个路由
28行:创建一个RoutesMiddleware对象,匹配路由,修改环境变量后,调用self._dispatch
4. 运行结果