flask/app.py-add_url_rule源碼分析


之前分析route方法的時候,可以看到中間會調用add_url_rule方法,add_url_rule方法和route方法一樣屬於Flask這個類的。

add_url_rule方法主要用來連接url規則。具體工作方法和route類似。如果提供了視圖函數,它將會和endpoint名字一起被注冊

#裝飾器使用方法:
@app.route('/')
def index():
    pass

# 等同與下面這種方法:
def index():
    pass
app.add_url_rule('/', 'index', index)

If the view_func is not provided you will need to connect the endpoint
               to a view function like so::
# 如果視圖函數沒有被提供,需要用下面語法把視圖函數和endpoint對應起來
 app.view_functions['index'] = index
  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)

        # 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
源代碼

參數解析:

  • rule: 一個字符串格式的url規則,如:"/login". 注:就是從route方法中調用add_url_rule是傳遞的rule
  • endpoint: url規則的名字,用來反向生成url使用,默認是視圖函數的名字。注:如果是route方法調用的,則這個參數是route方法傳遞過來的endpont
  • view_func: 視圖函數,當對應的endpoint名字被請求時需要調用的函數。注:如果時router方法點用的add_url_rule,則這個參數時router方法傳遞過來的f
  • options: 類似與分析route時候的options.這個options是跟隨:class:`~werkzeug.routing.Rule` object定義的,后面會分析這個對象中的具體參數,但有一個methods參數默認是只監聽get方法。注:如果是router方法點用的add_url_rule,則這個參數時router方法傳遞過來的options函數

函數體解析:

 1   def add_url_rule(self, rule, endpoint=None,  view_func=None, **options):
 2         if endpoint is None:
 3             # 如果沒有提供endpoint參數,則默認用view_func的名字
 4             endpoint = _endpoint_from_view_func(view_func)
 5         # 把endpoint參數添加到options里面
 6         options['endpoint'] = endpoint
 7         # 從options中pop出methods參數,並把值賦給methods變量,如果沒有則置為None
 8         methods = options.pop('methods', None)
 9         # moehods的值為None的情況下
10         if methods is None:
11             # 如果view_func函數中有這個methods參數,則使用view_func中的。如果沒有則賦一個列表('GET',)給methods
12             methods = getattr(view_func, 'methods', None) or ('GET',)
13         # 如果methods是字符串類型
14         if isinstance(methods, string_types):
15             # 拋出一個異常:methods需要是一個可以迭代的字符串
16             raise TypeError('Allowed methods have to be iterables of strings, '
17                             'for example: @app.route(..., methods=["POST"])')
18         # 把methods里面的item都改成大寫
19         methods = set(item.upper() for item in methods)
20 
21         # 在view_func里面定義了一個屬性required_methods = ()
22         # 作用:用來定義一些必須的方法,配合provide_automatic_options使用
23         required_methods = set(getattr(view_func, 'required_methods', ()))
24 
25         # starting with Flask 0.8 the view_func object can disable and
26         # force-enable the automatic options handling.
27         # 在view_func里面定義了一個屬性provide_automatic_options = None
28         # 作用:用於禁用和強制啟用一些自動選項
29         provide_automatic_options = getattr(view_func,
30             'provide_automatic_options', None)
31 
32         # 判斷provide_automati_options是否為None
33         if provide_automatic_options is None:
34             # 如果OPTIONS字符串沒有在methods里面
35             if 'OPTIONS' not in methods:
36                 # 則把provude_automatic_options改為True,並把OPTIONS添加到required_methods里面
37                 provide_automatic_options = True
38                 required_methods.add('OPTIONS')
39             # 如果OPTIONS在methods里面,則把provide_automatic_options設置為False
40             else:
41                 provide_automatic_options = False
42 
43         # 合並required_methods和methods這兩個集合到methods里面
44         methods |= required_methods
45         
46         # 創建路由規則
47         # 調用url_rule_class方法,由於在Flask類的全局變量中定義了:url_rule_class = Rule, Rule是werkzeug/routing.py里面的一個類
48         # 也就是相當於實例化了Rule得到了rule對象,具體實例化后的結果請看Rule源碼分析
49         rule = self.url_rule_class(rule, methods=methods, **options)
50         # 把provide_automatic_options屬性添加到rule對象里面
51         rule.provide_automatic_options = provide_automatic_options
52 
53         # 在Flask類的__init__里面定義了self.url_map = Map(),Map是werkzeug/routing.py里面的一個類
54         # self.url_map相當與實例化了Map,.add則是調用了Map類里面的add方法
55         # 具體運行結果,請參考Map源碼分析,以及Map源碼中的add方法分析
56         self.url_map.add(rule)
57         # 如果提供了view_func
58         if view_func is not None:
59             # 在flask類的__init__里面定義了self.view_functions = {},
60             # 從字典里面取endpoint值並賦值為old_func,(endpoint是傳遞的參數,默認為視圖函數名)
61             old_func = self.view_functions.get(endpoint)
62             # 如果old_func有值,並且不等於view_func
63             if old_func is not None and old_func != view_func:
64                 # 則拋出異常:視圖函數映射被一個已經存在的函數名重寫了
65                 # 也就是說已經存在了一個endpoint:old_func的映射,但是old_fun卻不是view_func,也就是說endpoint重復了
66                 raise AssertionError('View function mapping is overwriting an '
67                                      'existing endpoint function: %s' % endpoint)
68             # 添加視圖函數與endpoint映射到view_functions字典里面
69             self.view_functions[endpoint] = view_func

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM