如何理解 flask 中的 Blueprint 的 name 參數

Flask HTML 藕絲空間 2019-04-08

我一直以為 Blueprint 中的 name 參數和 url_for 中所用到的 endpoint (端點)有關,下面是我為什麼這樣理解的。

1、問題

通常我們在 flask 項目中使用藍圖的時候是這樣定義藍圖的:

admin = Blueprint('666', __name__)

其中,第一個參數究竟有什麼作用?能否隨便命名,或者乾脆不命名??

答案是 否定的!!!

2、解惑

首先,我們看一下 flask 的源碼: https://github.com/pallets/flask/blob/master/flask/blueprints.py

其中,有下面的代碼:

class Blueprint(_PackageBoundObject):
...
...
def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None,
root_path=None):
_PackageBoundObject.__init__(self, import_name, template_folder,
root_path=root_path)
self.name = name
self.url_prefix = url_prefix
self.subdomain = subdomain
self.static_folder = static_folder
self.static_url_path = static_url_path
self.deferred_functions = [] if url_defaults is None:
url_defaults = {}
self.url_values_defaults = url_defaults

上面的代碼可以明顯的看到, Blueprint 類繼承與 _PackageBoundObject,其中,name 參數,可是該類自己定義的,不是繼承的,那麼,我們繼續在源碼中查找 name 參數的作用。

在該類中尋找 self.name, 我們可以看到另外 8 處內容, 分別在該類的 before_request、afte\r_request、teardown_request、context_processor、url_value_preprocessor、url_defaults、errorhandler、register_error_handle 這 8 個類函數中,基本上函數中用到的地方都是:

 self.record_once(lambda s: s.app.before_request_funcs
.setdefault(self.name, []).append(f))

那麼,我們再看看這個 record_once 函數的作用,該函數也是在該類中定義的

 def record_once(self, func):
"""Works like :meth:`record` but wraps the function in another
function that will ensure the function is only called once. If the
blueprint is registered a second time on the application, the
function passed is not called.
"""
def wrapper(state):
if state.first_registration:
func(state) return self.record(update_wrapper(wrapper, func))

通過註釋,很明顯地看到這個函數的作用是為了將 name 參數作為唯一標識,在程序上下文中區分藍圖所用的。

那麼,回到原來的問題。

一、之所以可以隨便定義名稱,感覺沒有什麼影響,那是錯覺。

  • 第一個原因,很多時候,我們僅僅只是定義了一個藍圖,如果你再定義一個,你把 兩個藍圖的 name 參數設置成一樣的,你試試程序會不會報錯。
  • 第二個原因,沒有用到 url_for 函數,這個函數中會用到藍圖的 name 參數,或者我們直接這樣簡化的調用 url_for(‘.index’) 函數, 那個 ‘.’ 代表了當前的藍圖。
  • 還是回到 url_for 函數,如果在 html 的 jinja2 中調用,得這樣寫 url_for(‘name.index’),其中的 name 就是藍圖的 name 參數。

二、建議大家試試如果不定義 name 參數,程序會不會報錯。結果是必定報錯,因為這個參數是必須的。

  • 在 view 視圖中,我們使用 裝飾器 的寫法,一般是把函數名稱當做 endpoint 的,如果你在兩個不同的藍圖中,使用同一個名稱來定義視圖函數,那麼 endpoint 按照默認方案就無法是 唯一標識 了,必須得加上藍圖的名稱,所以藍圖的名稱也得是唯一的。


相關推薦

推薦中...