Python Routes map.resource详解

文档参考:

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>_”.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值