url->views,实现原理
Flask中的 路由设置与django的有很大的区别,因为,Flask的轻量级,所以,Flask的用法会更简单:
在views上面加上装饰器,app.route() 即可。url的命名,反向解析,接受的请求的格式的处理,这一切都只需要填写参数即可。
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 """ 可以看见,这个装饰器,本身执行的是 decorator方法, 在decorator中,调用了 add_url_rule 方法。 从方法的字面意思上理解,就是添加 url 到rule去。 下面看一下 add_url_rule的代码: """ def add_url_rule(self, rule, endpoint=None, view_func=None, provide_automatic_options=None, **options): if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) 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) required_methods = set(getattr(view_func, 'required_methods', ())) if provide_automatic_options is None: 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 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
看到上面的代码可以知道,Flask 建立url——》view 路由视图关系 正真的执行的是 add_url_rule() 函数,
并且,将路由(“/index”)这个封装了一个 Rule类,最后全部封装到了 url_map 里面。
所以,如果想要添加一个路由关系, 除了加装饰器之外还可以直接调用这个方法:
示例:
from flask import Flask app = Flask(__name__) app.config["DEBUG"] = True def index(): return "index" app.add_url_rule("/index", f=index) if __name__ == "__main__": app.run()
视图函数详解
- app.route()参数解析:
- rule: 路径; 字符串形式的例如: "/index"
- 路径添加参数:@app.route("/index/<int:id>"):
表示 从将id 传入视图函数, 且必须为int类型;
当有参数的时候, 在反向解析的时候, 需要将参数传入 例:url_for("index", nid=999 )
示例:
from flask import Flask app = Flask(__name__) app.config["DEBUG"] = True @app.route("/index/<int:id>") def index(id): print(id, type(id)) return "index" if __name__ == "__main__": app.run()
- 自定义路由中的参数类型:
- 自定义一个继承 BaseConverter 的类 从werkzeug.routing 中导入。
- app.url_map.converters["reg"] = 自定义的类
- 在app.route("/index/<reg(\d+):nid>")中使用。
- 当请求进来时会先实例化自定义的类,并且将nid的值传入到类中的to_python 函数中并调用
- 当在反向生成url的时候会执行 to_url 的函数,也就是说在CBV中的 url_for() 会先执行to_url 函数。
- 示例:
from flask import Flask from werkzeug.routing import BaseConverter class MyConverter(BaseConverter): def __init__(self, map, regex): super(MyConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 :param value: :return: """ return int(value) def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 :param value: :return: """ val = super(MyConverter, self).to_url(value) return val app = Flask(__name__) app.url_map.converters['reg'] = MyConverter @app.route('/index/<reg("\d+"):nid>') def index(nid): print(nid, type(nid)) print(url_for('index', nid=987)) return "index" if __name__ == '__main__': app.run()