Flask中路由模块的实现
在Flask中的路由功能主要通过修饰函数route实现,下面我们就来挖掘下route在源代码中是怎么分配视图函数的。
def route(self, rule, **options): def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
可以看出route是通过调用add_url_rule来添加路由功能的,endpoint负责与rule产生Rule类的,在add_url_rule中
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only ``GET`` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) if isinstance(methods, string_types): raise TypeError('Allowed methods have to be iterables of strings, ' 'for example: @app.route(..., methods=["POST"])') methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. provide_automatic_options = getattr(view_func, 'provide_automatic_options', None) if provide_automatic_options is None: if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS') else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError('View function mapping is overwriting an ' 'existing endpoint function: %s' % endpoint) self.view_functions[endpoint] = view_func
如果没有提供endpoint,_endpoint_from_view_function返回的是函数的__name__值作为这个函数的endpoint,后面设置了该试图函数支持的请求方法,之后产生Rule的实例,然后把这个实例添加到Map中,最后再记录endpoint和view_function的对应关系,以便将来得到请求时寻找到对应的视图函数。
其中的Rule和Map是在werkzeug所实现的。以下是Rule和Map的一般形式
url_map = Map([ Rule('/all/', defaults={'page': 1}, endpoint='all_entries'), Rule('/all/page/<int:page>', endpoint='all_entries') ])
Rule通过compile将rule转换成相对应的正则表达式如/all/page/<int:page>会被转换为r'/all/page/(?P<page>[0-9])'类似的形式,通过match会返回page的词典,也能基于提供的endpoint和dictory来构建相应的url,map则负责集合rule,调用map的bind方法会返回MapAdapter,这个类会处理多种重定向的情况以及调用视图函数。