简单了解Flask路由注册原理

因为平时在公司写后端代码都是基于Python的Flask框架,作为一个全栈(沾)工程师,我觉得有必要深入理解下框架的一些简单的原理。         首先我们就从路由说起,注册路由是我们平时工作最常写的东西,如果项目是MVC模式的话,我们更是基本每天都要注册路由来完成需求。但是,最常用的东西往往是最容易被忽略的,我们以为自己每天都在写,加上Python的装饰器这种魔法,我们想当然的认为自己对Flask框架的路由很了解。其实底层的源码很少有人看过,也没人真正想去了解其中的原理,可能这就是码农思维导致的一些弊病:只要能完成需求就行。

让我们先来看看常规的注册路由的方法:

@app.route('/index/', methods=('GET', 'POST'))
def index():
	pass
复制代码

我们先不说让无数人高潮的装饰器,确实,这个语法糖让Python代码变得很优雅。我们这里不讨论装饰器的利弊。但是,同样是注册路由,Flask还有一种方法也可以注册路由:

app.add_url_rule('/index', view_func=index)
复制代码

很明显这样的代码大家也能看出来,/index就是路由的名字,view_func变量就是视图函数,但是这样难免让人浮想联翩,因为我们知道装饰器的魔法,所以很容易让人把这两个注册路由的方法联系在一起。于是跟所有一样,我跳进了装饰器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
复制代码

看到这里很多人都懂了,原来装饰器实际调用的也是add_url_rule方法,只不过装饰器帮你做了这些而已,add_url_rule中rule函数就是我们传进去的路由名字(也叫路由规则),view_func函数就是视图函数,至于methods这些都是被包括在**options里面。源码中的注释也是写的很清楚,还给力例子让人理解,看来作者也是很暖心。既然作者那么暖男,那我们肯定不假思索地跳进去看add_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
复制代码

其实完全可以去看源码的注释,简直不要太全面,里面详细写了各种规则以及结合例子来说明这个函数的各个参数。我们挑重要和常用的几个来说:

endpoint

先让我们看看函数一开始的代码:

if endpoint is None:
	endpoint = _endpoint_from_view_func(view_func)
	options['endpoint'] = endpoint
复制代码

很明显,如果我们没有传入endpoint参数的话,endpoint就是view_func的值,也就是视图函数的名字,然后在options字典中添加endpoint的值。

method:

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)
复制代码

从注释中我们可以了解到methods的机制是很简单的,如果代码是我们一开始写的@app.route('/index', methods=['GET', 'POST']),那么路由可以接收get请求和post请求,没有传入methods的话methods = None。然后假如methods == None, 同时,view_func 没有methods属性的话,那么methods默认设置为('GET', ). 当然,methods不能设置为字符串类型,‘POST’可以不区分大小写。感觉源码就是在教你一样。。。。

rule:

:param rule: the URL rule as string
复制代码

注释里面有一句这样的话,意思就是传进来的路由名字是要字符串。

rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
复制代码

路由其实是相当复杂的,从上面的代码中可以看出来,self(Flask核心对象,就是app本身)其实是有一个url_rule_class属性,这个属性是一个Rule类的实例,这段代码中把路由规则和methods以及其他参数都装载到这个实例中,然后再放到url_mpa里面。这里有点绕,建议有兴趣的可以自己跳进去看源码理解。

结语

路由的简单的原理大概就是这些, 如果需要深入了解Flask的路由的话还需要看更多的源码以及去理解才行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值