文档参考:
http://routes.readthedocs.org/en/latest/introduction.html
demo参考:
http://blog.csdn.net/bellwhl/article/details/8956088
#!/usr/bin/env/python
#coding=utf-8
from routes import Mapper
from routes import middleware
import webob.dec
from wsgiref.simple_server import make_server
class controller(object):
def __init__(self):
self.i = 1
def __call__(self):
print self.i
def search(self):
return "do search()"
def show(self):
return "do show()"
def index(self):
return "do index()"
def update(self):
return "do update()"
def delete(self):
return "do delete()"
def create(self):
return "do create()"
def create_many(self):
return "do create_many()"
def update_many(self):
return "do update_many()"
def list_many(self):
return "do list_many()"
def delete_many(self):
return "do delete_many()"
def preview(self):
return "do preview()"
class appclass(object):
def __init__(self):
a = controller()
map = Mapper()
map.resource('message', 'messages', controller=a,
path_prefix='/{projectid}', name_prefix='lala_',
collection={'list_many': 'GET', 'create_many': 'POST'},
member={'update_many': 'POST', 'delete_many': 'POST'},
new={'preview' : 'POST'},
parent_resource=dict(member_name="haha", collection_name="heihei"))
self.route = middleware.RoutesMiddleware(self.dispatch, map)
@webob.dec.wsgify
def __call__(self, req):
return self.route
@staticmethod
@webob.dec.wsgify
def dispatch(req):
match = req.environ['wsgiorg.routing_args'][1]
route = req.environ['routes.route']
print "route match result is:", match
if not match:
return "fake url"
print "route.name: %s, route.routepath: %s, route.conditions: %s" % (route.name, route.routepath, route.conditions)
controller = match['controller']
action = match['action']
if hasattr(controller, action):
func = getattr(controller, action)
ret = func()
return ret
else:
return "has no action:%s" % action
if __name__ == "__main__":
app = appclass()
server = make_server('', 8088, app)
server.serve_forever()
1. GET http://127.0.0.1:8088/project_id_value/messages
do index()
route match result is: {'action': u'index', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>}
route.name: lala_messages, route.routepath: /{projectid}/messages, route.conditions: {'method': ['GET']}
2. POST http://127.0.0.1:8088/project_id_value/messages
do create()
route match result is: {'action': u'create', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>}
route.name: None, route.routepath: /{projectid}/messages, route.conditions: {'method': ['POST']}
3. PUT http://127.0.0.1:8088/project_id_value/messages/1
do update()
route match result is: {'action': u'update', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>, 'id': u'1'}
route.name: None, route.routepath: /{projectid}/messages/:(id), route.conditions: {'method': ['PUT']}
4. DELETE http://127.0.0.1:8088/project_id_value/messages/1
do delete()
route match result is: {'action': u'delete', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>, 'id': u'1'}
route.name: None, route.routepath: /{projectid}/messages/:(id), route.conditions: {'method': ['DELETE']}
5. GET http://127.0.0.1:8088/project_id_value/messages/1
do show()
route match result is: {'action': u'show', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>, 'id': u'1'}
route.name: lala_message, route.routepath: /{projectid}/messages/:(id), route.conditions: {'method': ['GET']}
6. POST http://127.0.0.1:8088/project_id_value/messages/new/preview
do preview()
route match result is: {'action': u'preview', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>}
route.name: lala_preview_new_message, route.routepath: /{projectid}/messages/new/preview, route.conditions: {'method': ['POST']}
7. GET http://127.0.0.1:8088/project_id_value/messages/list_many
do list_many()
route match result is: {'action': u'list_many', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>}
route.name: lala_list_many_messages, route.routepath: /{projectid}/messages/list_many, route.conditions: {'method': ['GET']}
8. POST http://127.0.0.1:8088/project_id_value/messages/create_many
do create_many()
route match result is: {'action': u'create_many', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>}
route.name: lala_create_many_messages, route.routepath: /{projectid}/messages/create_many, route.conditions: {'method': ['POST']}
9. POST http://127.0.0.1:8088/project_id_value/messages/1/update_many
do update_many()
route match result is: {'action': u'update_many', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>, 'id': u'1'}
route.name: lala_update_many_message, route.routepath: /{projectid}/messages/:(id)/update_many, route.conditions: {'method': ['POST']}
10. POST http://127.0.0.1:8088/project_id_value/messages/1/delete_many
do delete_many()
route match result is: {'action': u'delete_many', 'projectid': u'project_id_value', 'controller': <__main__.controller object at 0x0000000002E570F0>, 'id': u'1'}
route.name: lala_delete_many_message, route.routepath: /{projectid}/messages/:(id)/delete_many, route.conditions: {'method': ['POST']}
注释掉path_prefix行,如下:
map.resource('message', 'messages', controller=a,
# path_prefix='/{projectid}', name_prefix='lala_',
collection={'list_many': 'GET', 'create_many': 'POST'},
member={'update_many': 'POST', 'delete_many': 'POST'},
new={'preview' : 'POST'},
parent_resource=dict(member_name="haha", collection_name="heihei"))
重启启动,注意route.name和route.routepath属性的变动:
1. GET http://127.0.0.1:8088/heihei/haha_value/messages
do index()
route match result is: {'action': u'index', 'controller': <__main__.controller object at 0x0000000002D7A0F0>, 'haha_id': u'haha_value'}
route.name: haha_messages, route.routepath: /heihei/:haha_id/messages, route.conditions: {'method': ['GET']}
2. POST http://127.0.0.1:8088/heihei/haha_value/messages/new/preview
do preview()
route match result is: {'action': u'preview', 'controller': <__main__.controller object at 0x0000000002D7A0F0>, 'haha_id': u'haha_value'}
route.name: haha_preview_new_message, route.routepath: /heihei/:haha_id/messages/new/preview, route.conditions: {'method': ['POST']}
3. GET http://127.0.0.1:8088/heihei/haha_value/messages/list_many
do list_many()
route match result is: {'action': u'list_many', 'controller': <__main__.controller object at 0x0000000002D7A0F0>, 'haha_id': u'haha_value'}
route.name: haha_list_many_messages, route.routepath: /heihei/:haha_id/messages/list_many, route.conditions: {'method': ['GET']}
...
map.resource源码:
<span style="font-size:12px;">def resource(self, member_name, collection_name, **kwargs):
collection = kwargs.pop('collection', {})
member = kwargs.pop('member', {})
new = kwargs.pop('new', {})
path_prefix = kwargs.pop('path_prefix', None)
name_prefix = kwargs.pop('name_prefix', None)
parent_resource = kwargs.pop('parent_resource', None)
# Generate ``path_prefix`` if ``path_prefix`` wasn't specified and
# ``parent_resource`` was. Likewise for ``name_prefix``. Make sure
# that ``path_prefix`` and ``name_prefix`` *always* take precedence if
# they are specified--in particular, we need to be careful when they
# are explicitly set to "".
if parent_resource is not None:
if path_prefix is None:
path_prefix = '%s/:%s_id' % (parent_resource['collection_name'],
parent_resource['member_name'])
if name_prefix is None:
name_prefix = '%s_' % parent_resource['member_name']
else:
if path_prefix is None: path_prefix = ''
if name_prefix is None: name_prefix = ''
# Ensure the edit and new actions are in and GET
member['edit'] = 'GET'
new.update({'new': 'GET'})
# Make new dict's based off the old, except the old values become keys,
# and the old keys become items in a list as the value
def swap(dct, newdct):
"""Swap the keys and values in the dict, and uppercase the values
from the dict during the swap."""
for key, val in dct.iteritems():
newdct.setdefault(val.upper(), []).append(key)
return newdct
collection_methods = swap(collection, {})
member_methods = swap(member, {})
new_methods = swap(new, {})
# Insert create, update, and destroy methods
collection_methods.setdefault('POST', []).insert(0, 'create')
member_methods.setdefault('PUT', []).insert(0, 'update')
member_methods.setdefault('DELETE', []).insert(0, 'delete')
# If there's a path prefix option, use it with the controller
controller = strip_slashes(collection_name)
path_prefix = strip_slashes(path_prefix)
path_prefix = '/' + path_prefix
if path_prefix and path_prefix != '/':
path = path_prefix + '/' + controller
else:
path = '/' + controller
collection_path = path
new_path = path + "/new"
member_path = path + "/:(id)"
options = {
'controller': kwargs.get('controller', controller),
'_member_name': member_name,
'_collection_name': collection_name,
'_parent_resource': parent_resource,
'_filter': kwargs.get('_filter')
}
def requirements_for(meth):
"""Returns a new dict to be used for all route creation as the
route options"""
opts = options.copy()
if method != 'any':
opts['conditions'] = {'method':[meth.upper()]}
return opts
# Add the routes for handling collection methods
for method, lst in collection_methods.iteritems():
primary = (method != 'GET' and lst.pop(0)) or None
route_options = requirements_for(method)
for action in lst:
route_options['action'] = action
route_name = "%s%s_%s" % (name_prefix, action, collection_name)
self.connect("formatted_" + route_name, "%s/%s.:(format)" % \
(collection_path, action), **route_options)
self.connect(route_name, "%s/%s" % (collection_path, action),
**route_options)
if primary:
route_options['action'] = primary
self.connect("%s.:(format)" % collection_path, **route_options)
self.connect(collection_path, **route_options)
# Specifically add in the built-in 'index' collection method and its
# formatted version
self.connect("formatted_" + name_prefix + collection_name,
collection_path + ".:(format)", action='index',
conditions={'method':['GET']}, **options)
self.connect(name_prefix + collection_name, collection_path,
action='index', conditions={'method':['GET']}, **options)
# Add the routes that deal with new resource methods
for method, lst in new_methods.iteritems():
route_options = requirements_for(method)
for action in lst:
path = (action == 'new' and new_path) or "%s/%s" % (new_path,
action)
name = "new_" + member_name
if action != 'new':
name = action + "_" + name
route_options['action'] = action
formatted_path = (action == 'new' and new_path + '.:(format)') or \
"%s/%s.:(format)" % (new_path, action)
self.connect("formatted_" + name_prefix + name, formatted_path,
**route_options)
self.connect(name_prefix + name, path, **route_options)
requirements_regexp = '[^\/]+(?<!\\\)'
# Add the routes that deal with member methods of a resource
for method, lst in member_methods.iteritems():
route_options = requirements_for(method)
route_options['requirements'] = {'id':requirements_regexp}
if method not in ['POST', 'GET', 'any']:
primary = lst.pop(0)
else:
primary = None
for action in lst:
route_options['action'] = action
self.connect("formatted_%s%s_%s" % (name_prefix, action,
member_name),
"%s/%s.:(format)" % (member_path, action), **route_options)
self.connect("%s%s_%s" % (name_prefix, action, member_name),
"%s/%s" % (member_path, action), **route_options)
if primary:
route_options['action'] = primary
self.connect("%s.:(format)" % member_path, **route_options)
self.connect(member_path, **route_options)
# Specifically add the member 'show' method
route_options = requirements_for('GET')
route_options['action'] = 'show'
route_options['requirements'] = {'id':requirements_regexp}
self.connect("formatted_" + name_prefix + member_name,
member_path + ".:(format)", **route_options)
self.connect(name_prefix + member_name, member_path, **route_options)</span>
解释参数:
controller
Use the specified controller rather than deducing it from the collection name.
collection
Additional URLs to allow for the collection. Example:
member
Additional URLs to allow for a member. Example:
new
Additional URLs to allow for new-member functionality.
path_prefix
Prepend the specified prefix to all URL patterns. The prefix may include path variables. This is mainly used to nest resources within resources.
name_prefix
Prefix the specified string to all route names. This is most often combined with path_prefix to nest resources:
parent_resource
A dict containing information about the parent resource, for creating a nested resource. It should contain the member_name and collection_name of the parent resource. This dict will be available via the associated Route object which can be accessed during a request via request.environ["routes.route"].
If parent_resource is supplied and path_prefix isn’t, path_prefix will be generated from parent_resource as “<parent collection name>/:<parent member name>_id”.
If parent_resource is supplied and name_prefix isn’t, name_prefix will be generated from parent_resource as “<parent member name>_”.