Flask源碼分析:路由加載

Flask路由分析

from flask import Flask
app = Flask(__name__)
@app.route('/home')
def func():
    return "hello world"
# 在flask源碼中調用的就是add_url_rule方法,並把url和函數名傳進去
# app.add_url_rule("/home", view_func=func)
app.run()

------------------------------------------
def route(self, rule, **options):
    def decorator(f):
        endpoint = options.pop("endpoint", None)
        # rule= '/index',endpoint=None,f=func,**options={}
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator

@setupmethod
def add_url_rule(
    self,
    rule,   # rule= '/index'
    endpoint=None,
    view_func=None,     # view_func=func函數名
    provide_automatic_options=None,
    **options
    ):

    if endpoint is None:
        # _endpoint_from_view_func函數返回了view_func.__name__,也就是'func'
        endpoint = _endpoint_from_view_func(view_func)
    options["endpoint"] = endpoint  # {"endpoint":'func'}
    methods = options.pop("methods", None)  # methods = None

    if methods is None:
        # 若是func函數中沒有定義methods變量就,默認使用GET
        methods = getattr(view_func, "methods", None) or ("GET",)   # methods = ("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=set('get')

    # Methods that should always be added
    required_methods = set(getattr(view_func, "required_methods", ()))

    if provide_automatic_options is None:
        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   # False

    # Add the required methods now.
    methods |= required_methods
    # rule = Role('/index',methods=('get'),{"endpoint":'func'})
    # role對象.role='/index'
    rule = self.url_rule_class(rule, methods=methods, **options)    # ***********重點

    # Map對象.add(role對象)
    self.url_map.add(rule)
    if view_func is not None:
        # {}
        old_func = self.view_functions.get(endpoint)
        # {'func字符串':func函數名}
        self.view_functions[endpoint] = view_func


@implements_to_string
class Rule(RuleFactory):

    def __init__(
        self,
        string, # '/index',
        endpoint, # 'func'
    ):
        self.rule = string  # role對象.role = '/index'
        self.methods = set([x.upper() for x in methods])    # {"GET"}
        if "HEAD" not in self.methods and "GET" in self.methods:
            self.methods.add("HEAD")    # {"GET","HEAD"}

        self.endpoint = endpoint

    def bind(self, map, rebind=False):
        """能夠不看"""
        self.map = map  # 把map對象封裝到role對象裏 即role.map = map對象
        self.strict_slashes = map.strict_slashes    # self.strict_slashes = True
        self.subdomain = map.default_subdomain  # self.subdomain = ""
        self.compile()


class Map(object):
    def add(self, rulefactory):
        """
        :param rulefactory: role對象
        :return:
        """
        for rule in rulefactory.get_rules(self):
            # 如今的rule是role對象
            rule.bind(self) # self是map對象
            self._rules.append(rule)    # 空列表加入rule對象
            # {}.setdefault(rule.endpoint, []).append(rule)
            # {'func字符串':[rule對象,]}
            # {endpoint:[rule對象,]}
            self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
        self._remap = True

從上面的源碼分析中得出:

# app.view_functions = {'func字符串':func函數地址}
# app.map對象._rules_by_endpoint = [rule對象,]
# role對象.role = '/index'

1. app裏封裝了一個字典,字典中的鍵位:endpoint,值爲函數名
    {
        endpoint:函數名
    }


2. app裏封裝了一個map對象,在map對象中封裝了字典,字典的key爲endpoint字符串,value爲列表,列表裏放Role對象
    2.1 role對象裏封裝了url
        Map對象(
            {'endpoint':[Role對象,]}
        )
相關文章
相關標籤/搜索