首页 > 代码库 > python学习笔记-flask学习(一)

python学习笔记-flask学习(一)

以下是一个简单的能运行的flask示例代码,从该示例代码中分析Flask源码完成了哪些工作。

flask示例代码如下:

from flask import Flask

app = Flask(__name__)


@app.route(/)
def hello_world():
    return Hello World!

@app.route(/user/<name>)
def user(name):
    return <h1>Hello,%s!<h1>%name


if __name__ == __main__:
    app.run(debug=True)

首先调用app = Flask(__name__)构建一个Flask实例。Flask类定义在app.py文件中

 """The flask object implements a WSGI application and acts as the central
    object.  It is passed the name of the module or package of the
    application.  Once it is created it will act as a central registry for
    the view functions, the URL rules, template configuration and much more.

    The name of the package is used to resolve resources from inside the
    package or the folder the module is contained in depending on if the
    package parameter resolves to an actual python package (a folder with
    an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).

接下来分析app.route函数完成的工作

app.route是python的一个装饰器具体的函数代码如下:

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

在这里主要是通过调用add_url_rule函数将app实例与对应的视图函数关联起来

 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
如果没有指定endpoint函数_endpoint_from_view_func通过功能函数名指定为endpoint。接下来获取指定methods。url_rule_class(rule, methods=methods, **options)生成一rule的实例。接着url_map.add(rule)将rule与flask实例关联起来。在前面flask实例定义了Map对象的实例。
add函数的源码如下:
    def add(self, rulefactory):
        for rule in rulefactory.get_rules(self):
            rule.bind(self)
            self._rules.append(rule)
            self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
        self._remap = True

这里将map与rule关联起来。其中rule.bind()调用compile()对rule中的表达是进行了一次转义以‘/static/<path:filename>‘为例。

    def compile(self):

        if self.map.host_matching:
            domain_rule = self.host or ‘‘
        else:
            domain_rule = self.subdomain or ‘‘

        self._trace = []
        self._converters = {}
        self._weights = []
        regex_parts = []

        def _build_regex(rule):
            for converter, arguments, variable in parse_rule(rule):
                if converter is None:
                    regex_parts.append(re.escape(variable))
                    self._trace.append((False, variable))
                    for part in variable.split(/):
                        if part:
                            self._weights.append((0, -len(part)))
                else:
                    if arguments:
                        c_args, c_kwargs = parse_converter_args(arguments)
                    else:
                        c_args = ()
                        c_kwargs = {}
                    convobj = self.get_converter(
                        variable, converter, c_args, c_kwargs)
                    regex_parts.append((?P<%s>%s) % (variable, convobj.regex))
                    self._converters[variable] = convobj
                    self._trace.append((True, variable))
                    self._weights.append((1, convobj.weight))
                    self.arguments.add(str(variable))

        _build_regex(domain_rule)
        regex_parts.append(\\|)
        self._trace.append((False, |))
        _build_regex(self.is_leaf and self.rule or self.rule.rstrip(/))
        if not self.is_leaf:
            self._trace.append((False, /))

        if self.build_only:
            return
        regex = r^%s%s$ % (
            u‘‘.join(regex_parts),
            (not self.is_leaf or not self.strict_slashes) and
            (?<!/)(?P<__suffix__>/?) or ‘‘
        )
        self._regex = re.compile(regex, re.UNICODE)
_build_regex函数解析‘/static/<path:filename>‘。通过path去检索转换器
DEFAULT_CONVERTERS = {
    default:          UnicodeConverter,
    string:           UnicodeConverter,
    any:              AnyConverter,
    path:             PathConverter,
    int:              IntegerConverter,
    float:            FloatConverter,
    uuid:             UUIDConverter,
}

在routing文件中定义了PathConverter类。通过path字典中获取。在这里主要获取的是regex = ‘[^/].*?‘这个属性。然后regex_parts.append(‘(?P<%s>%s)‘ % (variable, convobj.regex))将‘filename‘和‘[^/].*?‘填充对应的字符。这里生成对应的

url正则表达式

 

 


python学习笔记-flask学习(一)