11. 蓝图

随着程序功能越来越多,为了便于组织,我们把程序功能进行模块化划分, 一个模块负责一类具体内务,这种结构称为蓝图。

简单来说,Blueprint 是一个存储操作方法的容器, Flask 可以通过Blueprint来组织URL以及处理请求。

Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:

  • 一个应用可以具有多个Blueprint
  • 在一个应用初始化时,就应该要注册需要使用的Blueprint
  • 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名, 即重复使用
  • 在一个应用中,一个模块可以注册多次
  • Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,也意味着蓝图可以和主程序基本没有耦合,可以随便复用

但是一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中,类似组件。

使用蓝图大概步骤:

  • 定义蓝图,在一个蓝图内完成一类任务
  • 使用蓝图,即注册蓝图,然后属于蓝图的访问会自动导入蓝图内进行处理

11.1. 蓝图使用案例

我们定义一个蓝图,在我们的教学业务中,学生的注册登录等管理属于用户模块 ,而相应的课程等属于课程模块,我们把这两个定义成蓝图使用。

  • 定义蓝图
    通过定义蓝图,定义的时候使用url_prefix来定义前缀url,这样相同 的前缀就会使用定义好的蓝图,蓝图此时相当于一个子路由。

    在下面代码中,我们定义了连个蓝图, bp1bp2, 每个分别对应不同的url前缀。

      # 导入Bluepoint
      from flask import Blueprint
    
      # 定义蓝图,注意参数,不懂的通过 ctr+点击, 进入源代码查看注释
      bp1 = Blueprint('user', __name__, url_prefix='/user')
      bp2 = Blueprint('teaching', __name__, url_prefix='/teaching')
    
      # 添加业务处理
    
      # 正常操作
      @bp1.route("/login")
      def user_login():
          return "User Login"
    
      # 正常操作
      @bp1.route("/reg")
      def user_reg():
          return "User Reg"
    
      # 正常操作
      @bp2.route("/get_course")
      def teaching_get_course():
          return "Teaching get_course"
    
      # 正常操作
      @bp2.route("/add_course")
      def teaching_add_course():
          return "Teaching add_course"
    
  • 使用蓝图
    蓝图的使用相对简单,直接导入后注册,如果url前缀符合定义的话就会自动的调用蓝图处理。

      from flask import Flask
    
      # 导入庄子啊蓝图的文件
      import bp_apps
    
      app = Flask(__name__)
    
      app.register_blueprint(bp_apps.bp1)
      app.register_blueprint(bp_apps.bp2)
    
      if __name__ == "__main__":
          app.run()
    

在经过上述定义后,我们访问相应url后会有蓝图进行相应处理,比如 访问
http://127.0.0.1:5000/teaching/add_course
后会显示对应蓝图的对应处理结果。

11.2. 蓝图运行机制

  • 蓝图保存了一组将来可以在应用对象上执行的操作
  • 当在应用对象上调用 route 装饰器注册路由时,这个操作将修改对象的url_map路由表
  • 蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项
  • 当执行应用对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的路由表

11.3. 蓝图的url前缀

  • 当我们在应用对象上注册一个蓝图时,可以指定一个url_prefix关键字参数(这个参数默认是/)

  • 在应用最终的路由表 url_map中,在蓝图上注册的路由URL自动被加上了这个前缀, 这个可以保证在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在注册蓝图时将不同的蓝图挂接到不同的自路径即可

  • url_for 蓝图中更可以使用url_for, 我们在蓝图定义的时候会定义蓝图的name关键字值,在 地下路由中也会使用endpoint定义端点名称,如果需要使用url_for,则可以直接用点号操作。

      # name='user'
      bp1 = Blueprint('user', __name__, url_prefix='/user')
      ... ...
    
      # endpoint='test'
      @bp1.route("/test", endpoint='test')
      def user_test():
          # 返回的时候使用点号操作
          return  url_for("user.test")