flask_之URL
URL篇
在分析路由匹配过程之前,我们先来看看 flask
中,构建这个路由规则的两种方法:
-
通过
@app.route()
decorator -
通过
app.add_url_rule
,这个方法的签名为add_url_rule(self, rule, endpoint=None, view_func=None, **options)
,参数的含义如下:-
rule
: url 规则字符串,可以是静态的/path
,也可以包含/
-
endpoint
:要注册规则的 endpoint,默认是view_func
的名字 -
view_func
:对应 url 的处理函数,也被称为视图函数
-
这两种方法是等价的,也就是说:
@app.route('/') def hello(): return "hello, world!"
也可以写成
def hello(): return "hello, world!" app.add_url_rule('/', 'hello', hello)
其实,还有一种方法来构建路由规则——直接操作 app.url_map
这个数据结构。不过这种方法并不是很常用,因此就不展开了
静态路由
@app.route('/') def hello_world(): # 变量可以通过赋值传到前端,前端可以通过Jinja语法{{}}渲染 return render_template('t1.html', name='t1', age=16) @app.route('/services') def services(): return 'Services' @app.route('/about') def about(): return 'About' # 相对projects解释类似于文件夹解释形式,指向某一个文件夹下的某个文件 @app.route('/projects/') @app.route('/projects_our') # 可以定义多个URL到同一个视图函数上,Flask支持 def projects(): return 'Projects' @app.route('/login',methods=["GET","POST"]) def login(): return render_template('login.html', req_method=request.method)
动态路由
# 动态路由 @app.route('/user/<username>') def user(username): print username return username # 路由转换器:指定参数类型 # flask提供3种:int(整形)|float(浮点型)|path(路径,并支持一个/) @app.route('/user/<int:user_id>') def user(user_id): print user_id return 'User_id:%s'%user_id
自定义路由规则
# flask不提供正则表达的形式的URL匹配 # 可通过定义完成 # 1、from werkzeug.routing import BaseConverter # 2、自定义类 #转换器 class RegexConverter(BaseConverter): def __init__(self,url_map,*items): super(RegexConverter,self).__init__(self) # print items # (u'[a-z]{3}[A-Z]{3}',) # print url_map # URL 的一个MAP对象,类似路由表 self.regex = items[0] # 3、要将定义的类注册到APP的url_map中,定义名称 # app.url_map.converters['regex'] = RegexConverter # 4、使用 @app.route('/user/<regex("[a-z]{3}[A-Z]{3}"):username>') def user(username): print username return 'Username:%s' % username
浅析源码
注册路由规则的时候,flask 内部做了哪些东西呢?我们来看看 route
方法:
def route(self, rule, **options): """A decorator that is used to register a view function for a given URL rule. This does the same thing as :meth:`add_url_rule` but is intended for decorator usage. """ def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
route
方法内部也是调用 add_url_rule
,只不过在外面包了一层装饰器的逻辑,这也验证了上面两种方法等价的说法
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): """Connects a URL rule. Works exactly like the :meth:`route` decorator. If a view_func is provided it will be registered with the endpoint. """ 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 和构建 methods 的部分逻辑,可以看到它主要做的事情就是更新 self.url_map
和 self.view_functions
两个变量。找到变量的定义,发现 url_map
是 werkzeug.routeing:Map
类的对象,rule
是 werkzeug.routing:Rule
类的对象,view_functions
就是一个字典。这和我们之前预想的并不一样,这里增加了 Rule
和 Map
的封装,还把 url
和 view_func
保存到了不同的地方。
需要注意的是:每个视图函数的 endpoint 必须是不同的,否则会报 AssertionError
。
未完待续。。。