python学习笔记-flask学习(二)BulePrint

  app.route定义的装饰器只有在app实例创建后才能运行。如果需要将app之前是由route来添加路由规则和功能或者将路由和app接耦合,在这种场景下Blueprint提供很好的解决方法。在蓝本定义的路由规则处于休眠状态,直到这个蓝图注册到app中。

  蓝图定义: 

auth = Blueprint('auth',__name__)

@auth.route('/logout')
def logout():
    pass

这里完成的工作只是创建一个蓝图并将路由加入蓝图中

from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint,url_prefix='/auth')

这里将蓝图中注册的路由添加到app实例中。下面来分析下蓝图的工作原理:

auth.route('/logout')装饰器的源码如下

    def route(self, rule, **options):
        """Like :meth:`Flask.route` but for a blueprint.  The endpoint for the
        :func:`url_for` function is prefixed with the name of the blueprint.
        """
        def decorator(f):
            endpoint = options.pop("endpoint", f.__name__)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

route调用add_url_rule函数,add_url_rule函数其实是调用record函数将下面的一个匿名函数对象传入到deferred_functions的列表中,这个在register将调用注册这些匿名函数。add_url_rule函数代码如下:

    def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
        """Like :meth:`Flask.add_url_rule` but for a blueprint.  The endpoint for
        the :func:`url_for` function is prefixed with the name of the blueprint.
        """
        if endpoint:
            assert '.' not in endpoint, "Blueprint endpoints should not contain dots"
        self.record(lambda s:
            s.add_url_rule(rule, endpoint, view_func, **options))

到此蓝图中注册路由就完成了。接下来是注册实现的原理

首先调用Flask对象的register_blueprint函数,这个函数调用blueprint的register处理处理蓝图的注册。

    def register_blueprint(self, blueprint, **options):
        """Registers a blueprint on the application.

        .. versionadded:: 0.7
        """
        first_registration = False
        if blueprint.name in self.blueprints:
            assert self.blueprints[blueprint.name] is blueprint, \
                'A blueprint\'s name collision occurred between %r and ' \
                '%r.  Both share the same name "%s".  Blueprints that ' \
                'are created on the fly need unique names.' % \
                (blueprint, self.blueprints[blueprint.name], blueprint.name)
        else:
            self.blueprints[blueprint.name] = blueprint
            self._blueprint_order.append(blueprint)
            first_registration = True
        blueprint.register(self, options, first_registration)
blueprint的register函数调完成了一下功能首先make_setup_state创建了BlueprintSetupState实例。然后将这个实例作为deferred_functions中存储的匿名函数的入参。调用的BlueprintSetupState的add_rule_url函数,而在
BlueprintSetupState的add_rule_url函数其实最终调用的flask的add_rule_url
blueprint的register函数
    def register(self, app, options, first_registration=False):
        """Called by :meth:`Flask.register_blueprint` to register a blueprint
        on the application.  This can be overridden to customize the register
        behavior.  Keyword arguments from
        :func:`~flask.Flask.register_blueprint` are directly forwarded to this
        method in the `options` dictionary.
        """
        self._got_registered_once = True
        state = self.make_setup_state(app, options, first_registration)
        if self.has_static_folder:
            state.add_url_rule(self.static_url_path + '/<path:filename>',
                               view_func=self.send_static_file,
                               endpoint='static')

        for deferred in self.deferred_functions:
            deferred(state)
    def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
        """A helper method to register a rule (and optionally a view function)
        to the application.  The endpoint is automatically prefixed with the
        blueprint's name.
        """
        if self.url_prefix:
            rule = self.url_prefix + rule
        options.setdefault('subdomain', self.subdomain)
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        defaults = self.url_defaults
        if 'defaults' in options:
            defaults = dict(defaults, **options.pop('defaults'))
        self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint),
                              view_func, defaults=defaults, **options)

 

posted @ 2017-04-19 23:38  BillHust  阅读(3001)  评论(0编辑  收藏  举报