1. 程式人生 > >從app.route裝飾器引發對endpoint的思考

從app.route裝飾器引發對endpoint的思考

從app.route裝飾器引發對endpoint的思考
還是先來看看原始碼

    def route(self, rule, **options):
        """A decorator that is used to register a view function for a
        given URL rule.  This does the same thing as :meth:`add_url_rule`
        but is intended for decorator usage::

            @app.route('/')
            def index():
                return 'Hello World'

        For more information refer to :ref:`url-route-registrations`.

        :param rule: the URL rule as string
        :param endpoint: the endpoint for the registered URL rule.  Flask
                         itself assumes the name of the view function as
                         endpoint
        :param options: the options to be forwarded to the underlying
                        :class:`~werkzeug.routing.Rule` object.  A change
                        to Werkzeug is handling of method options.  methods
                        is a list of methods this rule should be limited
                        to (``GET``, ``POST`` etc.).  By default a rule
                        just listens for ``GET`` (and implicitly ``HEAD``).
                        Starting with Flask 0.6, ``OPTIONS`` is implicitly
                        added and handled by the standard request handling.
        """
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

route傳入了**options這樣一個字典,一般我們會傳方法methods進去,GET、POST,如果不自己設定endpoint=....的話預設就是No。
然後進入add_url_rule函式看一看:

def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options['endpoint'] = endpoint
        methods = options.pop('methods', None)
...
...
...
        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為None,會呼叫_endpoint_from_view_func函式來給endpoint賦值,
看一下_endpoint_from_view_func的程式碼:

def _endpoint_from_view_func(view_func):
    """Internal helper that returns the default endpoint for a given
    function.  This always is the function name.
    """
    assert view_func is not None, 'expected view func if endpoint ' \
                                  'is not provided.'
    return view_func.__name__

可以看到將檢視函式名賦值給了endpoint,所以如果我們建立檢視函式時不在**options中指明endpoint的話,預設就是檢視函式名,
後半部分進行了判斷,保證了endpoint的唯一,並將view_func儲存在view_functions這個字典中,並且和endpoint形成對映關係,還將路徑加入到當前應用中, 這樣做的好處是,當我們用url_for()從一個endpoint來找到一個URL時,可以順著這個對映關係來找,而不用寫URL, 常見的用法是url_for(blueprint.endpoint,parm=val...)進行重定向,這樣可以獲取一個檢視函式的路徑,傳給redirect(),
redirect(location,code=302)函式會把接收的引數作為響應body中的Location欄位返回給客戶端,並且預設是302臨時重定向。

def redirect(location, code=302, Response=None):
...
...
    #為Location欄位賦值,返回給客戶端進行重定向
    response.headers['Location'] = location
            return response

總結:
URL《————》endpoint《————》view
一個檢視函式的endpoint如果不設定那麼就是檢視函式名。
為URL和view搭起橋樑,使得整個後端框架更加靈活。
url_for(.endpoint)返回的是檢視函式對應的URL,URL是對應檢視函式裝飾器傳入的值。