pecan源码阅读(三)

装饰器

装饰器定义在decorators.py中,其中最重要的就是expose,它标识了这个被装饰的方法可以被路由找到

def when_for(controller):
    def when(method, **kw):
        def decorate(f):
            _cfg(f)['generic_handler'] = True
            controller._pecan['generic_handlers'][method.upper()] = f
            controller._pecan['allowed_methods'].append(method.upper())
            expose(**kw)(f)
            return f
        return decorate
    return when

// template:标识了渲染模板,默认moko,
// generic:默认的方法处理所有类型的请求(GET,POST,PUT,DELETE),如果为true,则各种类型的请求分开处理
// route:自定义路由
def expose(template=None,
           generic=False,
           route=None,
           **kw):
    content_type = kw.get('content_type', 'text/html')
    if template == 'json':
        content_type = 'application/json'
    def decorate(f):
        # flag the method as exposed
        f.exposed = True

        cfg = _cfg(f)
        cfg['explicit_content_type'] = 'content_type' in kw

        if route:
            # This import is here to avoid a circular import issue
            from pecan import routing
            if cfg.get('generic_handler'):
                raise ValueError(
                    'Path segments cannot be overridden for generic '
                    'controllers.'
                )
            routing.route(route, f)

        # set a "pecan" attribute, where we will store details
        cfg['content_type'] = content_type
        cfg.setdefault('template', []).append(template)
        cfg.setdefault('content_types', {})[content_type] = template

        # handle generic controllers
        if generic:
            if f.__name__ in ('_default', '_lookup', '_route'):
                raise ValueError(
                    'The special method %s cannot be used as a generic '
                    'controller' % f.__name__
                )
            cfg['generic'] = True
            cfg['generic_handlers'] = dict(DEFAULT=f)
            cfg['allowed_methods'] = []
            // 方法可以被类似@index.when()装饰
            f.when = when_for(f)

        # store the arguments for this controller method
        // 参数
        cfg['argspec'] = getargspec(f)

        return f
    return decorate

1.cfg = _cfg(f)代码为方法指定了参数_pecan,dict对象,其中存储了该方法很多重要信息
2. cfg[‘generic_handlers’] = dict(DEFAULT=f) 当generic为true时,其中存储了具体的处理方法,{‘generic_handlers’:{‘DEFAULT’:function,‘POST’:function,‘PUT’:function}},当请求时POST,PUT,DELETE等方式时,就是从其中获取处理方法
3. f.when = when_for(f)

// 看似是对index_post方法进行装饰,但是主要还是对index方法进行处理
// 这里把index_post方法添加到index方法的_pecan['generic_handlers']中
// 这个写法很有意思,大家可以借鉴
@index.when(method='POST')
def index_post(self):
	pass

根据POST,PUT,DELETE路由

在routing.py中find_object方法会返回找到的subcontroller,它是有@expose装饰的一个方法

def find_object(obj, remainder, notfound_handlers, request):
   ...
   ...

        # Last-ditch effort: if there's not a matching subcontroller, no
        # `_default`, no `_lookup`, and no `_route`, look to see if there's
        # an `index` that has a generic method defined for the current request
        # method.
        if not obj and not notfound_handlers and hasattr(prev_obj, 'index'):
            if request.method in _cfg(prev_obj.index).get('generic_handlers',
                                                          {}):
                return prev_obj.index, prev_remainder

在core.py中根据POST具体找到相应的方法

def find_controller(self, state):
   ...
   ...

        if cfg.get('generic'):
            im_self = six.get_method_self(controller)
            handlers = cfg['generic_handlers']
            // 根据POST找到处理方法
            controller = handlers.get(req.method, handlers['DEFAULT'])
            handle_security(controller, im_self)
            cfg = _cfg(controller)

所以最终找到处理方法是在core.py中,其实这里我认为处理的不好,还是应该在routing.py中处理

这里有几个写的不好的地方:
1.当请求为/v1//books这种不标准的形式的时候,pecan的路由机制是没法处理的

        try:
            next_obj, rest = remainder[0], remainder[1:]
            // 可以将这里改成 if next_obj == '' and not rest  解决该问题
            if next_obj == '':
                index = getattr(obj, 'index', None)
                if iscontroller(index):
                    return index, rest
    def route(self, req, node, path):
    	// 可以将list中最后的空字符串删除,这个需和第一点配合
        path = path.split('/')[1:]

3.对于 POST /v1/books/safgrgfwsfrsg (最后的一个segment没有定义,并且没有定义_lookup和_default),这是依然能够找到路由方法,但是会在参数处理的时候报错,这个地方不合理

def find_object(obj, remainder, notfound_handlers, request):
		...
		...
        try:
            obj = getattr(obj, next_obj, None)
        except UnicodeEncodeError:
            obj = None
            
		// 添加这段代码规避该问题
		###########
		if not obj and not notfound_handlers and remainder:
			abort(404)
		##########
		
        # Last-ditch effort: if there's not a matching subcontroller, no
        # `_default`, no `_lookup`, and no `_route`, look to see if there's
        # an `index` that has a generic method defined for the current request
        # method.
        if not obj and not notfound_handlers and hasattr(prev_obj, 'index'):
            if request.method in _cfg(prev_obj.index).get('generic_handlers',
                                                          {}):
                return prev_obj.index, prev_remainder

上面3点对源码的改动可以完成我们自定义的一些需求,并且是pecan的代码结构更加合理
(有兴趣的可以去github上提issue)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Pecan Street是美国德克萨斯州奥斯汀市的一个社区,也是一个研究机构。它是一个旨在推动可持续发展和智能城市发展的平台。 Pecan Street社区位于奥斯汀市中心,由家庭住宅、商业建筑和研发中心组成。这个社区致力于探索和应用科技创新,以改善能源效率、水资源管理、交通运输和社会互动等方面的可持续性。 Pecan Street研究机构是一个非营利组织,与德州大学奥斯汀分校合作,致力于使用先进技术研究和开发创新的解决方案,以实现可持续发展的目标。他们与各个领域的合作伙伴合作,包括政府机构、能源供应商、科技公司等,共同探索解决方案,以改善能源使用、环境保护和生活质量。 Pecan Street社区和研究机构的重点是智能电网技术和能源系统。他们利用先进的传感器、物联网、大数据分析等技术,收集和分析能源使用数据,以帮助居民和研究人员更好地了解和优化能源消耗。此外,他们还为居民提供关于可再生能源系统、储能技术和能源效率的培训和支持。 总之,Pecan Street是一个以可持续发展和智能城市发展为目标的社区和研究机构。他们通过应用创新技术和合作伙伴关系,致力于改善能源效率、水资源管理、交通运输和社会互动等方面的可持续性。他们的工作对于推动环境保护和提升生活质量具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值