可以翻譯成“視圖入口”,就是個名字。url_for可以用到,其他方面也可以用到(比如導航條確定當前頁面),因為endpoint在一個 app 里唯一對應到一個 view function。
翻譯整理自Stack Overflow:http://stackoverflow.com/questions/19261833/what-is-an-endpoint-in-flask
原文中用到了my_greeting視圖函數/端點,我估計是答者筆誤,故修改為了give_greeting。
Flask路由是如何工作的
整個flask框架(及以Werkzeug類庫為基礎構建的應用)的程序理念是把URL地址映射到你想要運行的業務邏輯上(最典型的就是視圖函數),例如:
@app.route('/greeting/')defgive_greeting(name):return'Hello, {0}!'.format(name)
注意,add_url_rule函數實現了同樣的目的,只不過沒有使用裝飾器,因此,下面的程序是等價的:
# 抬頭沒有使用路由裝飾器,我們在最后用另一種方法添加路由.defgive_greeting(name):return'Hello, {0}!'.format(name)app.add_url_rule('/greeting/','give_greeting', give_greeting)
備注:add_url_rule()中3個參數依次是rule、view_func、endpoint.
假設www.example.org站點定義了以上視圖,用戶在瀏覽器中輸入以下地址
http://www.example.org/greeting/Mark
Flask的工作就是捕捉這個URL地址,弄清用戶想要做什么,并在眾多的Python函數中匹配一個可以處理它的函數,回到我們的實例中,URL地址就是
/greeting/Mark
拿著這個地址到路由表中做匹配,flask發現這個地址指向了give_greeting函數。
然而,當我們用這種最常用的方法創建視圖時,flask卻向我們隱藏了一些其他的細節信息。在這個場景中,flask并沒有直接從URL地址跳轉到應該響應它請求的視圖函數上:
URL (http://www.example.org/greeting/Mark) 被視圖函數處理 ("give_greeting"函數)
事實上,這里還有另一個步驟--把URL地址映射到端點上(URL-->endpoint-->viewfunction):
URL (http://www.example.org/greeting/Mark) 映射到端點"give_greeting"上.指向端點"give_greeting"的請求被視圖函數"give_greeting"處理.
從根本上來說,端點就是程序中一組邏輯處理單元的ID,該ID對應的代碼決定了對此ID請求應該作出何種響應。通常,端點與視圖函數同名,但是你也可以修改它,例如:
@app.route('/greeting/', endpoint='say_hello')defgive_greeting(name):return'Hello, {0}!'.format(name)
現在就成了這樣:
URL (http://www.example.org/greeting/Mark) 映射到端點"say_hello"上.指向端點"say_hello"的請求被視圖函數"give_greeting"處理.
Endpoint有什么作用
端點通常用作反向查詢URL地址(viewfunction-->endpoint-->URL)。例如,在flask中有個視圖,你想把它關聯到另一個視圖上(或從站點的一處連接到另一處)。不用去千辛萬苦的寫它對應的URL地址,直接使用URL_for()就可以啦:
@app.route('/')def index():? ? print url_for('give_greeting', name='Mark') # 打印出'/greeting/Mark'@app.route('/greeting/')def give_greeting(name):? ? return'Hello, {0}!'.format(name)
備注:url_for()中give_greeting是端點名.
這樣做是大有裨益的:我們可以隨意改變應用中的URL地址,卻不用修改與之關聯的資源的代碼。
為何要多此一舉
那么問題來了:為何要多此一舉,為何要先把URL映射到端點上,再通過端點映射到視圖函數上,為何不跳過中間的這個步驟?
原因就是采用這種方法能夠使程序更高、更快、更強。例如藍本。藍本允許我們把應用分割為一個個小的部分,現在admin藍本中含有超級管理員級的資源,user藍本中則含有用戶一級的資源。
藍本允許咱們把應用分割為一個個以命名空間區分的小部分:
main.py:
fromflaskimportFlask, Blueprintfromadminimportadminfromuserimportuserapp = Flask(__name__)app.register_blueprint(admin, url_prefix='admin')app.register_blueprint(user, url_prefix='user')
admin.py:
admin = Blueprint('admin', __name__)@admin.route('/greeting')defgreeting():return'Hello, administrative user!'
user.py:
user = Blueprint('user', __name__)@user.route('/greeting')defgreeting():return'Hello, lowly normal user!'
注意,在兩個藍本中路由地址'/greeting'的函數都叫"greeting"。如果我想調用admin對應的greeting函數,我不能說“我想要greeting”,因為這里還有一個user對應的greeting函數。端點這時就發揮作用了:指定一個藍本名稱作為端點的一部分--通過這種方式端點實現了對命名空間的支持。所以,我們可以這樣寫:
printurl_for('admin.greeting') # Prints'/admin/greeting'printurl_for('user.greeting') # Prints'/user/greeting'
來發實例
fromflaskimportFlask, url_forapp = Flask(__name__)# We can use url_for('foo_view') for reverse-lookups in templates or view functions@app.route('/foo')deffoo_view():pass# We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!@app.route('/bar', endpoint='bufar')defbar_view():passwithapp.test_request_context('/'):print(url_for('foo_view'))#/fooprint(url_for('bufar'))#/bar# url_for('bar_view') will raise werkzeug.routing.BuildErrorprint(url_for('bar_view'))#端點bar_view是沒有定義的
程序運行結果
python_endpoint_程序運行結果
更多參考: