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对象,]}
        )
posted @ 2019-12-01 19:31  影印  阅读(116)  评论(0编辑  收藏  举报
……