对于 Flask 最外围的有三点:

  • Application Context: 将整个利用连成一体.
  • View Function & CLI Command: 利用暴漏给外界的操作接口
  • Blueprints (蓝图): 实现模块化开发

当然还有其余细节,但有了这三点,就能够编写一个残缺的 Web 援用了

Application Context

参考: Flask 2.0.x

我更习惯应用 工厂模式 创立 Context: 在 __init__.py 中写 create_app():

from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()def create_app(test_config=None):    # create and configure the app    app = Flask(__name__, instance_relative_config=True)    configure(app, test_config)    db.init_app(app)    from faq.blueprints import review    app.register_blueprint(review.bp)    return app

当在命令行输出命令 flask run 时, flask 将主动寻找 create_app 函数来执行, 以创立 Application Context.

PS: flask run 便是一个默认的 CLI Command

默认在 View Function 和 CLI Command 中主动就在 以后利用的 Context 下. 而此外其余的场景下, 须要手动的创立/引入 Application Context. flask-sqlalchemy 中的例子:

with app.app_context():    user = db.User(...)    db.session.add(user)    db.session.commit()

但实际上 有 View Function 和 CLI 就足够了

View Functions & CLI Command

View Function 次要做到了门路和函数的映射绑定, 同时借助 Flask 其余的模块 (request, current_app, make_response 等), 取得参数和返回响应

参考: Flask 2.0.x Doc

这是一个 View Function 的例子.

bp = Blueprint('review_show', __name__, url_prefix='/review/show', cli_group=None)@bp.route('/requests/<user_id>', methods=['GET'])def show_requests(user_id):    page = int(request.args.get('page'))    per_page = int(request.args.get('page_size'))    data: dict = request.get_json()    print(data)    current_app.logger.info("request user id: %s", user_id)    requests: Pagination = ERequest.query \        .order_by(ERequest.time.desc()) \        .paginate(page=int(page), per_page=int(per_page), error_out=False)    body = [RequestEntry(rq) for rq in requests.items]    return make_response(jsonify(body), 200)

取得 param 参数:

page = int(request.args.get('page'))per_page = int(request.args.get('page_size'))

取得json 格局的 request body:

data: dict = request.get_json()print(data)

响应

return make_response(jsonify(body), 200)

接下来是 CLI Command:

参考:

  • custom-commands,
  • testing-cli-commands: 蕴含了两种参数 (option, argument) 的用法
bp = Blueprint('review_show', __name__, cli_group='cli')@bp.cli.command('test')@click.option('--who', default='tom')@click.argument('what', default='good morning')def hello(who, what):    print(f'hello: {who},{what}')

运行:

PS D:\my\flask\app> $env:FLASK_APP = "faq"PS D:\my\flask\app> flask cli hellohello: tom,good morningPS D:\my\flask\app> flask cli hello goodby --who bobhello: bob,goodbyPS D:\my\flask\app>

Blueprints 蓝图

从 Java 转来的我非常心愿实现像 Spring boot Controller 那样的多模块开发. 行将不同类型或不同需要模块的 API 放在不同的 Controller 中, 而后通过命名加以辨别.

Blueprints 就实现了这点. 蓝图能够注册到 app 中去, 同时又能够注册其余子蓝图, 从而能够实现一个树状的注册构造.

比方, 这是我的文件目录

│  models.py│  __init__.py│└─blueprints   │  __init__.py   │   └─ review     │  handle.py     │  show.py     └─ __init__.py

/blueprints/show.py 中 我定义了具体的 View Functions 和 CLI

bp = Blueprint('review_show', __name__, url_prefix='/review/show', cli_group='cli')@bp.cli.command('hello')@click.option('--who', default='tom')@click.argument('what', default='good morning')def hello(who, what):    print(f'hello: {who},{what}')@bp.route('/requests/<user_id>', methods=['GET'])def show_requests(user_id):    pass

这个蓝图 review_show 注册到另一个蓝图 review 中:

/blueprints/review/__init__.py:

from flask import Blueprintfrom faq.blueprints.review import show, handlebp = Blueprint('review', __name__)bp.register_blueprint(show.bp)bp.register_blueprint(handle.bp)

最终, 蓝图 review 注册到 app 中:

/__init__.py:

def create_app(test_config=None):    ......    from faq.blueprints import review    app.register_blueprint(review.bp)    return app