天天看點

Flask中'endpoint'(端點)的了解

翻譯整理自Stack Overflow:http://stackoverflow.com/questions/19261833/what-is-an-endpoint-in-flask

原文中用到了

my_greeting

視圖函數/端點,我估計是答者筆誤,故修改為了

give_greeting

Flask路由是如何工作的

整個flask架構(及以Werkzeug類庫為基礎建構的應用)的程式理念是把URL位址映射到你想要運作的業務邏輯上(最典型的就是視圖函數),例如:

@app.route('/greeting/<name>')
def give_greeting(name):
    return 'Hello, {0}!'.format(name)
           

注意,add_url_rule函數實作了同樣的目的,隻不過沒有使用裝飾器,是以,下面的程式是等價的:

# 擡頭沒有使用路由裝飾器,我們在最後用另一種方法添加路由.
def give_greeting(name):
    return 'Hello, {0}!'.format(name)

app.add_url_rule('/greeting/<name>', '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/<name>', endpoint='say_hello')
def give_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/<name>')
def give_greeting(name):
    return 'Hello, {0}!'.format(name)
           
備注:url_for()中

give_greeting

是端點名.

這樣做是大有裨益的:我們可以随意改變應用中的URL位址,卻不用修改與之關聯的資源的代碼。

為何要多此一舉

那麼問題來了:為何要多此一舉,為何要先把URL映射到端點上,再通過端點映射到視圖函數上,為何不跳過中間的這個步驟?

原因就是采用這種方法能夠使程式更高、更快、更強。例如藍本。藍本允許我們把應用分割為一個個小的部分,現在admin藍本中含有超級管理者級的資源,user藍本中則含有使用者一級的資源。

藍本允許咱們把應用分割為一個個以命名空間區分的小部分:

main.py:

from flask import Flask, Blueprint
from admin import admin
from user import user

app = 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')
def greeting():
    return 'Hello, administrative user!'
           

user.py:

user = Blueprint('user', __name__)
@user.route('/greeting')
def greeting():
    return 'Hello, lowly normal user!'
           

注意,在兩個藍本中路由位址‘/greeting’的函數都叫

"greeting"

。如果我想調用admin對應的

greeting

函數,我不能說“我想要greeting”,因為這裡還有一個user對應的

greeting

函數。端點這時就發揮作用了:指定一個藍本名稱作為端點的一部分–通過這種方式端點實作了對命名空間的支援。是以,我們可以這樣寫:

print url_for('admin.greeting') # Prints '/admin/greeting'
print url_for('user.greeting') # Prints '/user/greeting'
           

來發執行個體

from flask import Flask, url_for

app = Flask(__name__)

# We can use url_for('foo_view') for reverse-lookups in templates or view functions
@app.route('/foo')
def foo_view():
    pass

# We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!
@app.route('/bar', endpoint='bufar')
def bar_view():
    pass

with app.test_request_context('/'):
    print (url_for('foo_view'))  #/foo
    print (url_for('bufar'))  #/bar
    # url_for('bar_view') will raise werkzeug.routing.BuildError
    print (url_for('bar_view'))  #端點bar_view是沒有定義的
           

程式運作結果

Flask中'endpoint'(端點)的了解

更多參考:

http://www.cnblogs.com/eric-nirnava/p/endpoint.html