flask_之URL

URL篇

在分析路由匹配過程以前,咱們先來看看 flask 中,構建這個路由規則的兩種方法:html

  1. 經過 @app.route() decorator前端

  2. 經過 app.add_url_rule,這個方法的簽名爲 add_url_rule(self, rule, endpoint=None, view_func=None, **options),參數的含義以下:python

    • rule: url 規則字符串,能夠是靜態的 /path,也能夠包含 /flask

    • endpoint:要註冊規則的 endpoint,默認是 view_func 的名字api

    • view_func:對應 url 的處理函數,也被稱爲視圖函數數據結構

這兩種方法是等價的,也就是說:app

@app.route('/')
def hello():
    return "hello, world!"

 也能夠寫成ide

def hello():
    return "hello, world!"

app.add_url_rule('/', 'hello', hello)

 其實,還有一種方法來構建路由規則——直接操做 app.url_map 這個數據結構。不過這種方法並非很經常使用,所以就不展開了函數

靜態路由

@app.route('/')
def hello_world():
    # 變量能夠經過賦值傳到前端,前端能夠經過Jinja語法{{}}渲染
    return render_template('t1.html', name='t1', age=16)

@app.route('/services')
def services():
    return 'Services'
@app.route('/about')
def about():
    return 'About'

# 相對projects解釋相似於文件夾解釋形式,指向某一個文件夾下的某個文件
@app.route('/projects/')
@app.route('/projects_our') # 能夠定義多個URL到同一個視圖函數上,Flask支持
def projects():
    return 'Projects'

@app.route('/login',methods=["GET","POST"])
def login():
    return render_template('login.html', req_method=request.method)

 動態路由

# 動態路由
@app.route('/user/<username>')
def user(username):
    print username
    return username

# 路由轉換器:指定參數類型
# flask提供3種:int(整形)|float(浮點型)|path(路徑,並支持一個/)
@app.route('/user/<int:user_id>')
def user(user_id):
    print user_id
    return 'User_id:%s'%user_id

 自定義路由規則

# flask不提供正則表達的形式的URL匹配
# 可經過定義完成
# 一、from werkzeug.routing import BaseConverter
# 二、自定義類
#轉換器
class RegexConverter(BaseConverter):
    def __init__(self,url_map,*items):
        super(RegexConverter,self).__init__(self)
        # print items # (u'[a-z]{3}[A-Z]{3}',)
        # print url_map # URL 的一個MAP對象,相似路由表
        self.regex = items[0]

# 三、要將定義的類註冊到APP的url_map中,定義名稱
# app.url_map.converters['regex'] = RegexConverter

# 四、使用
@app.route('/user/<regex("[a-z]{3}[A-Z]{3}"):username>')
def user(username):
    print username
    return 'Username:%s' % username

 淺析源碼

註冊路由規則的時候,flask 內部作了哪些東西呢?咱們來看看 route 方法:ui

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.
    """

    def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f

    return decorator
route

route 方法內部也是調用 add_url_rule,只不過在外面包了一層裝飾器的邏輯,這也驗證了上面兩種方法等價的說法

def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
    """Connects a URL rule.  Works exactly like the :meth:`route`
    decorator.  If a view_func is provided it will be registered with the
    endpoint.
    """
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options['endpoint'] = endpoint
        methods = options.pop('methods', None)

        # if the methods are not given and the view_func object knows its
        # methods we can use that instead.  If neither exists, we go with
        # a tuple of only ``GET`` as default.
        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 that should always be added
        required_methods = set(getattr(view_func, 'required_methods', ()))

        # starting with Flask 0.8 the view_func object can disable and
        # force-enable the automatic options handling.
        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

        # Add the required methods now.
        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
add_url_rule

上面這段代碼省略了處理 endpoint 和構建 methods 的部分邏輯,能夠看到它主要作的事情就是更新 self.url_mapself.view_functions 兩個變量。找到變量的定義,發現 url_mapwerkzeug.routeing:Map 類的對象,rulewerkzeug.routing:Rule 類的對象,view_functions 就是一個字典。這和咱們以前預想的並不同,這裏增長了 RuleMap 的封裝,還把 urlview_func 保存到了不一樣的地方。

須要注意的是:每一個視圖函數的 endpoint 必須是不一樣的,不然會報 AssertionError

未完待續。。。

相關文章
相關標籤/搜索