簡單瞭解Flask路由註冊原理

由於平時在公司寫後端代碼都是基於Python的Flask框架,做爲一個全棧(沾)工程師,我以爲有必要深刻理解下框架的一些簡單的原理。         首先咱們就從路由提及,註冊路由是咱們平時工做最常寫的東西,若是項目是MVC模式的話,咱們更是基本天天都要註冊路由來完成需求。可是,最經常使用的東西每每是最容易被忽略的,咱們覺得本身天天都在寫,加上Python的裝飾器這種魔法,咱們想固然的認爲本身對Flask框架的路由很瞭解。其實底層的源碼不多有人看過,也沒人真正想去了解其中的原理,可能這就是碼農思惟致使的一些弊病:只要能完成需求就行。python

讓咱們先來看看常規的註冊路由的方法:後端

@app.route('/index/', methods=('GET', 'POST'))
def index():
	pass
複製代碼

咱們先不說讓無數人高潮的裝飾器,確實,這個語法糖讓Python代碼變得很優雅。咱們這裏不討論裝飾器的利弊。可是,一樣是註冊路由,Flask還有一種方法也能夠註冊路由:app

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函數的源碼:ide

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

先讓咱們看看函數一開始的代碼:post

if endpoint is None:
	endpoint = _endpoint_from_view_func(view_func)
	options['endpoint'] = endpoint
複製代碼

很明顯,若是咱們沒有傳入endpoint參數的話,endpoint就是view_func的值,也就是視圖函數的名字,而後在options字典中添加endpoint的值。ui

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’能夠不區分大小寫。感受源碼就是在教你同樣。。。。url

rule:

:param rule: the URL rule as string
複製代碼

註釋裏面有一句這樣的話,意思就是傳進來的路由名字是要字符串。spa

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的路由的話還須要看更多的源碼以及去理解才行。

相關文章
相關標籤/搜索