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

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

大道至简

# app.py
from flask import Flask
app = Flask(__name__)
@app.route("/xxx/yyy/<int:id>", 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/<int:id>", 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才真的做到了能屈能伸。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342