封尘网

让学习成为一种习惯!

flask 项目中使用蓝图的方法

Flask 用 蓝图(blueprints) 的概念来在一个应用中或跨应用制作应用组件和支持通用的模式。蓝图很好地简化了大型应用工作的方式,并提供给 Flask 扩展在应用上注册操作的核心方法。一个 Blueprint 对象与 Flask 应用对象的工作方式很像,但它确实不是一个应用,而是一个描述如何构建或扩展应用的 蓝图 。

简单来说:就是视图方法模块化,蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合.

为什么使用蓝图?
Flask 中的蓝图为这些情况设计:

把一个应用分解为一个蓝图的集合。这对大型应用是理想的。一个项目可以实例化一个应用对象,初始化几个扩展,并注册一集合的蓝图。
以 URL 前缀和/或子域名,在应用上注册一个蓝图。 URL 前缀/子域名中的参数即成为这个蓝图下的所有视图函数的共同的视图参数(默认情况下)。
在一个应用中用不同的 URL 规则多次注册一个蓝图。
通过蓝图提供模板过滤器、静态文件、模板和其它功能。一个蓝图不一定要实现应用或者视图函数。
初始化一个 Flask 扩展时,在这些情况中注册一个蓝图。
Flask 中的蓝图不是即插应用,因为它实际上并不是一个应用——它是可以注册,甚至可以多次注册到应用上的操作集合。为什么不使用多个应用对象?你可以做到那样 (见 应用调度 ),但是你的应用的配置是分开的,并在 WSGI 层管理。

蓝图作为 Flask 层提供分割的替代,共享应用配置,并且在必要情况下可以更改所注册的应用对象。它的缺点是你不能在应用创建后撤销注册一个蓝图而不销毁整个应用对象。

1.下图是我们通常情况下使用的项目组织结构

flask-demo
----app
    ----static
        ----admin
            ----css
            ----images
            ----js
        ----user
            ----css
            ----images
            ----js
    ----templates
        ----admin
            ----index.html
        ----user
            ----index.html     
        ----base.html
    ----__init__.py            #初始化app程序的文件,称为工厂文件
    ----models.py              #保存数据库建表的models
    ----migrate.py             #数据库的迁移,更新文件
    ----views.py               #主程序app的视图函数,同时也是注册蓝图的主要文件
----config.py                  #通用的配置文件,如数据库连接配置。
----manage.py                  #命令管理工作,集成DB,运行命令
views.py 文件的内容:
from app import app
@app.route('/user/index')
def index():
    return 'user_index'

@app.route('/user/show')
def show():
    return 'user_show'

@app.route('/user/add')
def add():
    return 'user_add'

@app.route('/admin/index')
def adminindex():
    return 'admin_index'

@app.route('/admin/show')
def adminshow():
    return 'admin_show'

@app.route('/admin/add')
def adminadd():
    return 'admin_add'

从视图方法中,我们看到有6个视图,分别对应admin,user两个不同用户的3个功能index,add,show.
这样写显然没问题,但是明显与python提倡的模块化,优雅的代码特点相违背.

让我们在这里假想两个问题:

  • 如果admin和user不止只有3个功能呢,比如好几百个,导致views的代码量已经达到了上万行?
  • 如果我们有多个同事分工开发admin,user和其它可能的模块呢,都同时往一个views里写代码吗,在做版本控制时,提交过程中频繁出现提交冲突了怎么办?
  • 加入我们要抛弃admin或者user功能块时怎么办,要一一手动删除所有admin或是user相关的代码吗,这样当然可以,但是会不会太low呢?

蓝图的杀手锏是将你的应用组织成不同的组件,比如把这里的admin,user相关的视图方法分为两个组件,一个是admin组件,一个是user组件.这时我们可以

创建两个蓝图实现这两个独立的组件.

由于上面的例子中只有两个组件(模块)admin,user,我们可以创建名为admin.py和user.py的两个文件,分别在里面创建两个蓝图的实例对象admin,user.

admin.py
from flask import Blueprint,render_template, request

admin = Blueprint('admin',__name__)

@admin.route('/index')
def index():
    return render_template('admin/index.html')

@admin.route('/add')
def add():
    return 'admin_add'

@admin.route('/show')
def show():
    return 'admin_show'

要想创建一个蓝图对象,你需要import flask.Blueprint()类并用参数name和importname初始化。importname通常用`__name`,一个表示当前模块的特殊的Python变量,作为import_name的取值。

user.py
from flask import Blueprint, render_template, redirect

user = Blueprint('user',__name__)

@user.route('/index')
def index():
    return render_template('user/index.html')

@user.route('/add')
def add():
    return 'user_add'

@user.route('/show')
def show():
    return 'user_show'

好了,视图函数已经分开了,我们如何使用它们的呢?再来看一下我们的views.py变成了什么样吧?
views.py

from app import app
from .admin import admin
from .user import user
  • 这里分别给app注册了两个蓝图admin,user
  • 参数url_prefix=’/xxx’的意思是设置request.url中的url前缀,
  • 即当request.url是以/admin或者/user的情况下才会通过注册的蓝图的视图方法处理请求并返回
    app.register_blueprint(admin,url_prefix='/admin')
    app.register_blueprint(user, url_prefix='/user')
    

现在我们的views是否已经变得很简单了呢?顺便回答第三个问题,如果想弃用某一个组件(模块)我们只需要相对应的注释掉给app注册蓝图的行即可.

细心的伙伴还可以发现,在views.py中在使用默认endpoint的前提下,我们是没有办法使用同一个视图方法名的(当然我们也不建议在同一个文件中有两个视图方法名相同,尽管指向他们的request.url不同),但是使用了蓝图之后我们就可以在不同模块中使用相同的方法名了.

提醒:本文最后更新于 36 天前,文中所描述的信息可能已发生改变,请谨慎使用。