学会蓝图为什么对Flask项目至关重要?

初学flask时,惊艳于flask的小巧和简洁,对于一个接口性质,尤其主要功能都是由脚本完成的项目而言,相较于臃肿的Django而言,flask简直是天作之合。

大道至简

# app.py
from flask import Flask
app = Flask(__name__)
@app.route("/xxx/yyy/", methods=["POST", "GET"])
def test(id):
    print(id)
    return "your parameter is %d" % id

if __name__ == "__main__":
    app.run()

没错,最基本的代码就是这么一个文件,这么几行代码。只需要把test函数改为你的调用入口,一个基于脚本功能的API接口就搭建起来了!
想输出json格式也很简单,可以导入jsonify,然后格式化一下,就像这样:

# app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/xxx/yyy/", methods=["POST", "GET"])
def test(id):
    return jsonify(method="login")

if __name__ == "__main__":
    app.run()

你就能得到这样的效果啦:

{"method":"login"}

less is more

但是这里面有一个问题,就是所有文件我们都写在了这个带着app.run()方法的文件里,这个叫app.py的文件是flask项目的启动入口。如果我们的API很多怎么办呢?比如这样的目录结构:

  • account:
    • login
    • logout
    • register
  • user:
    • update_profile
    • change_password
  • order:
    • order_list
    • order_detail

......

我们实际中写的项目的规模远远大于上面我写的东西。那么,问题来了:

  1. 一个单文件,但代码量却在万行以上的项目,要我们如何维护?
  2. 如何实现中间件功能,比如访问修改用户资料时先检查用户是否登录呢?
  3. 如何分工协作?

交给蓝图吧

以上种种问题,蓝图都是可以搞定的。
怎么理解蓝图呢,我想用零售行业的例子来解释一下。
之前的那个app.py相当于厂家。厂家我们把所有功能都写在里面,就好比这个厂家是生产销售一把抓。
蓝图(Blueprint)可以被看做是一个代理商,厂家把生产出来的产品直接给代理商就行了。厂家可以专心做生产,销售任务就全交给代理商就好了。
代理商不负责终端销售,一般我们买东西访问的门店都分布在各个商圈。这些门店,厂家是不关心的。
所以这个模式,就是一个厂家对几个代理商,每个代理商对几个门店,呈现出一个树形结构。
同理,在flask里面,一个app.py对应多个蓝图,每个蓝图再对应多个视图函数。
如图所示:


blueprint.png

还是基于上面的user, account, order的需求,我们用蓝图来实现,目录结构可以是这样的:

  • app.py
  • views
    • _init_.py
    • account.py
    • user.py
    • order.py

每个文件大概是这个样子:

  1. app.py变得很纯粹了,从views目录导入了Flask示例(app对象),然后执行。
# app.py
from views import app

if __name__ == '__main__':
    app.run()
  1. 我们在views目录的init文件里实例化了Flask对象,导入了每个功能块的蓝图实例(blue_account对象等),并将这些蓝图实例注册到了flask实例中。
# views/__init__.py
from flask import Flask
from .account import blue_account
from .user import blue_user
from .order import blue_order

app = Flask(__name__)

app.register_blueprint(blue_account)
app.register_blueprint(blue_user)
app.register_blueprint(blue_order)
  1. 以account为例,我们实例化了一个蓝图实例(blue_account),并通过蓝图实例的route方法进行url和函数的映射。
    蓝图具有app的大部分方法,我们基本都可以直接平移使用。
    不仅如此,我们在实例化蓝图对象时,还可以指定url_prefix参数,实现url地址的目录化,进行逻辑归类。
# views/account.py
from flask import Blueprint, jsonify

blue_account = Blueprint("account", __name__, url_prefix="/account")
@blue_account.route("/login", methods=["GET", "POST"])
def login():
    return jsonify(method="login")

@blue_account.route("/logout", methods=["GET"])
def logout():
    return "logout"

如此一来,每一个文件的代码都不会看起来冗长,且不同的逻辑进行了物理分离。这样的代码,条理清晰,即能够让不同的人负责不同的模块,修改起来也能很容易的找到相应的代码了。

如果我要实现中间件呢?

没问题。以user为例。我们可以通过before_request装饰器来实现。

from flask import Blueprint
blue_user = Blueprint("user", __name__, url_prefix="/user")

# 通过before_request实现类似中间的功能
@blue_user.before_request
def check_auth():
    if not session.get("auth"):
        return redirect("/account/login")

@blue_user.route("/update_profile", methods=["GET", "POST"])
def update_profile():
    return "update_profile"

增加蓝图功能的注意事项

  1. 迁移步骤
    如果你之前所有的代码都写在了app.py里,那么看完这篇文章后,你就可以做迁移了。迁移的步骤大概包括:
  1. 在app.py平级目录下,创建一个新的目录用来放置功能代码;
  2. 在业务目录下,根据业务分类,新建N个py文件,并将对应的代码剪切过来;
  3. 在py文件的上方,实例化蓝图对象,并把原先用app写的装饰器,改为蓝图;
  4. 在业务目录下,新建_init_.py,把实例化flask的代码放进来,并导入步骤3中创建出来的蓝图对象;
  1. 注意事项
  • 如果你使用了文件配置,要注意sys.path里,默认的项目根目录仍然在app.py所在的目录中。所以修改时,需要带上目录名。
app = Flask(__name__)
# 原先的写法,导入settings.py里的DevConfig块
# app.config.from_object("settings.DevConfig")
# 使用蓝图后,settings.py会放入业务目录中做配置分离,那么导入时要加上views目录才行
app.config.from_object("views.settings.DevConfig")
  • 如果在页面或跳转时使用了别名,也需要加上蓝图的名字
# 之前如果是这么写的
def checkAuth():
    # 判断逻辑
    return redirect( url_for("login") )
# 使用蓝图之后,需要这么写
def checkAuth():
    # 判断逻辑
    return redirect( url_for("account.login") )
  • 实例化蓝图对象的小细节:
    (1)前两个参数是必填的,第一个参数是name,也就是我们用url_for的时候使用的名字;
    (2)第二个参数是import_name,一般都写name,其实就是文件名;
    (3)返回值用于被_init_.py中做导入;
    (4)参数可以做定制化,如url_prefix用于做url的目录结构划分,template_folder可以自定义模板目录,static_folder可以自定义静态文件目录;

学会了蓝图,我们的flask项目就可以实现类似Django的多APP模块分离的结构了,这样有利于我们做功能划分,url目录结构化,配置隔离化等等,flask才真的做到了能屈能伸。

你可能感兴趣的:(学会蓝图为什么对Flask项目至关重要?)