那flask是如何将路由与视图函数绑定的呢?在Flask类的内部是这样定义的:
def route(self, rule, **options): def decorator(f): self.add_url_rule(rule, f.__name__, **options) self.view_functions[f.__name__] = f return f return decorator self.view_functions = {} def add_url_rule(self, rule, endpoint, **options): options[‘endpoint‘] = endpoint options.setdefault(‘methods‘, (‘GET‘,)) self.url_map.add(Rule(rule, **options)) self.url_map = Map()
可以看到,route定义了一个装饰品,通过add_url_rule方法将URL与视图函数的名字(即enpoint)绑定,并通过view_function字典将开发者定义的函数添加到视图函数里,形式为{ 函数名: 函数 }。也就是说,URL并不直接与处理函数绑定。URL是与endpoint绑定,而endpoint才与处理函数绑定。endpoint与处理函数通过view_fuction{}字典映射,这很好理解,不过URL与endpoint的绑定就需要多花点心思来理解了,因为引入了werkzeug中的Map和Rule。Map和Rule从字面上很容易理解 为“所有映射关系”和“产生一对新的映射关系”。
Flask类中dispatch_request()方法使用了view_fuction{}字典:
def dispatch_request(self): try: endpoint, values = self.match_request() return self.view_functions[endpoint](**values) except HTTPException, e: handler = self.error_handlers.get(e.code) if handler is None: return e return handler(e) except Exception, e: handler = self.error_handlers.get(500) if self.debug or handler is None: raise return handler(e)
获取endpoint的关键在于match_request()方法:
def match_request(self): """Matches the current request against the URL map and also stores the endpoint and view arguments on the request object is successful, otherwise the exception is stored. """ rv = _request_ctx_stack.top.url_adapter.match() request.endpoint, request.view_args = rv return rv
这里的match方法是werkzeug中MapAdapter类定义的方法。
>>> m = Map([ ... Rule(‘/‘, endpoint=‘index‘), ... Rule(‘/downloads/‘, endpoint=‘downloads/index‘), ... Rule(‘/downloads/<int:id>‘, endpoint=‘downloads/show‘) ... ]) >>> urls = m.bind("example.com", "/") >>> urls.match("/", "GET") (‘index‘, {}) >>> urls.match("/downloads/42") (‘downloads/show‘, {‘id‘: 42}) And here is what happens on redirect and missing URLs: >>> urls.match("/downloads") Traceback (most recent call last): ... RequestRedirect: http://example.com/downloads/ >>> urls.match("/missing") Traceback (most recent call last): ... NotFound: 404 Not Found
这里展示了Map和Rule的主要几个功能:映射关系的添加、绑定和匹配。
总结一下路由匹配的过程:
- 通过@app.route或app.add_url_map()将URL和endpoint绑定,将
- endpoint和处理函数绑定。
- 将请求URL通过match方法取得endpoint及相关参数。
- 通过view_fuction{}字典获取endpoint对应的函数,将相关参数传入,进行处理。
时间: 2024-10-07 10:33:39