多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 第二章 起步与红图 本章我们初始化项目,探讨与研究Flask的默认层级结构。当我们遇到层级结构不合理时,我们将模仿蓝图自己定义一个“红图”来扩展Flask层级体系 ### 2-1 环境、开发工具与flask1.0 ### 2-2 初始化项目 ### 2-3 新建入口文件 当我们拿到一个全新的 `flask`项目的时候,我们如何开始呢?第一件事情就是给项目建立入口文件。文件名一般与项目同名,比如当前项目名为 `ginger`,入口文件名为 `ginger.py`。 入口文件创建完成之后,首先要考虑的是如何拿到 `flask`核心对象。正如之前课程讲到的,不推荐在入口文件中实例化 `flask`核心对象,推荐在项目根目录下新建 `app`包(就是个含有`__init__`文件的目录,目录名字叫做 `app`),然后在 `app`包下新建`app.py`文件,我们把与 `flask`核心对象初始化相关的工作都放到`app.py`中。 ### 2-4 蓝图分离视图函数的缺陷 ### 2-5 打开思维,创建自己的Redprint——红图 ![](https://ws4.sinaimg.cn/large/006tKfTcgy1g0r544s92gj31u10u04qp.jpg) ### 2-6 实现 Redprint > 疑问: > > `Redpoint`的 `register`方法其实什么都没有干,仅仅是传入参数进来了,这样也行?为什么呢? > > * `if`语句是为了加 `url`前缀 > > * `for`语句是为了注册路由 > ~~~  class RedPrint:      def __init__(self, name):          self.name = name          self.mound = []  ​      def route(self, rule, **options):          def decorator(f):              self.mound.append((f, rule, options))              return f          return decorator  ​      def register(self, bp, url_prefix=None):          if url_prefix is None:              url_prefix = '/' + self.name          for f, rule, options in self.mound:              endpoint = options.pop("endpoint", f.__name__)              bp.add_url_rule(url_prefix + rule, endpoint, f, **options) ~~~ #### 知识点1 `options` 到底是什么类型的数据呢?它是一个字典; 字典的 `pop`方法是什么意思呢?是取到某一个值,并且将原来字典里的值删除掉。 这里用法精妙的地方就在于`pop`后面还有`f.__name__`,这个意思是取默认值。因为 `options`里并不一定有以 `endpoint`为键的值。这句话的意思就是,如果 `options`里有以 `endpoint`为键的值,那么就取这个值;如果 `options`里没有以`endpoint`这个键,就取`f.__name__`(视图函数的名字)作为 `endpoint`的名字。这是非常精妙的,这就是一种非常 pythonic 的写法! 我们可以在视图函数里传入 `endpoint`: ~~~  @api.route('/', methods=['GET'], endpoint=xxx)  def get_book():      return 'get book' ~~~ 如果你在这里传入 `endpoint`的话,那么 `options`里面就有 `endpoint`这个键,就能取到值。 大多数情况下,我们都不会传 `endpoint`,所以说大多数情况下 `endpoint` 就是视图函数的名字。 #### 知识点2 前缀 `url_prefix` `add_url_rule`第一个参数是**路由规则**,所以此处第一个参数应该为 `url_prefix + rule` ### 2-7 优化 Redpoint 我们在 app.api.v1.**init**.py 文件中注册 Redpoint 的时候每次都需要写 `url_prefix`有点烦,我们可不可以不传 `url_prefix`呢? ~~~  def create_blueprint_v1():      bp_v1 = Blueprint('v1', __name__)            user.api.register(bp_v1, url_prefix='/user')      book.api.register(bp_v1, url_prefix='/book')      client.api.register(bp_v1, url_prefix='/client')      return bp_v1 ~~~ 答案是可以的。因为传入的 `url_prefix`与`Redpoint`名称是相同的,我们完全可以使用 `Redpoint`的名称来代替 `url_prefix`。在 `Redpoint.register`函数中添加如下判断就行了: ~~~  if url_prefix is None:      url_prefix = '/' + self.name ~~~ 表明,如果不传 `url_prefix`的话,则默认使用`/+self.name`来表示`url_prefix`。