• Flask蓝本(Blueprint)


    一、动态配置Flask app

    在使用单个文件开发Flask应用程序时,由于Flask对象app是在全局作用域中创建的,在运行这个全局文件脚本时,app就已经创建,所以此时修改app的配置是不会生效的。为了解决这个问题可以把app的创建移到可显式调用的工厂函数中,即延迟创建app实例。

    工厂函数:app/__init__.py

    from flask import Flask, render_template
    from flask_sqlalchemy import SQLAlchemy
    from flask_wtf.csrf import CSRFProtect
    
    from config import config
    
    db = SQLAlchemy()
    csrf = CSRFProtect()
    
    
    # 创建Flask实例,注册第三方扩展,调用config.init_app初始化
    def create_app(config_name):
        app = Flask(__name__)
        app.config.from_object(config[config_name])
        config[config_name].init_app(app)
    
        db.init_app(app)   # 注册第三方扩展
        csrf.init_app(app)
    
        return app  # 返回app实例
    

    此时调用create_app()即可动态传入config_name参数实现动态配置。

    二、使用蓝本

    使用工厂函数创建app实例可以解决了动态配置的问题,但是程序路由应该如何配置呢?我们在使用单个文件开发Flask程序时,在全局作用域创建了app实例,直接使用app.route就可配置路由,而现在app实例的创建已经移到工厂函数中进行了,只有调用工厂函数create_app后才能使用app实例,然而我们的路由函数在编写程序时已经定义好了,也就是说在编写路由函数时是无法获取到app实例的,也就无法定义路由配置。通用的所有需要在编码时使用app实例的配置此时都无法使用。

    为了解决这个问题flask提供了蓝本。

    蓝本:app/main/__init__.py

    from flask import Blueprint
    
    main = Blueprint('main', __name__)  # 创建蓝本
    
    from . import  views   # 在views定义程序的路由
    

    在views中定义的程序路由只有在蓝本注册到app实例上后才有效。

    # 创建Flask实例,注册第三方扩展,调用config.init_app初始化
    def create_app(config_name):
        app = Flask(__name__)
        app.config.from_object(config[config_name])
        config[config_name].init_app(app)
    
        db.init_app(app)
        csrf.init_app(app)
    
        from .main import main as main_blueprint  # 导入蓝本
        app.register_blueprint(main_blueprint)  # 注册蓝本
    
        return app
    

    完整的(app/__init__.py)

    from flask import Flask, render_template
    from flask_sqlalchemy import SQLAlchemy
    from flask_wtf.csrf import CSRFProtect
    
    from config import config
    
    db = SQLAlchemy()
    csrf = CSRFProtect()
    
    
    # 创建Flask实例,注册第三方扩展,调用config.init_app初始化
    def create_app(config_name):
        app = Flask(__name__)
        app.config.from_object(config[config_name])
        config[config_name].init_app(app)
    
        db.init_app(app)
        csrf.init_app(app)
    
        #注册蓝本
        from .main import main as main_blueprint
        from .auth import auth as auth_blueprint
        app.register_blueprint(main_blueprint)
        app.register_blueprint(auth_blueprint, url_prefix = '/auth')
    
        return app
    

    views.py

    from datetime import datetime
    
    from flask import render_template, session, redirect, url_for
    
    from . import main # 导入蓝本
    
    
    @main.route('/home', methods = ['GET', 'POST']) # 定义路由
    def index():
        return render_template('welcome.html')
    

    三、定义程序启动脚本

    manage.py

    import os
    
    
    from flask_script import Manager, Shell
    from flask_migrate import Migrate, MigrateCommand
    
    from app import create_app
    from app import db
    
    app = create_app(os.getenv('FLASK_CONFIG') or 'default')
    manager = Manager(app)
    migrate = Migrate(app, db)
    
    
    def make_shell_context():
        return dict(app=app, db=db)
    
    
    manager.add_command('shell', Shell( make_context = make_shell_context() ) )
    manager.add_command('db', MigrateCommand)
    
    if __name__ == '__main__':
        manager.run()
    

    在定义程序脚本时需要使用Flask-Script和Flask-Migrate包。运行python manage.py即可启动程序。

    四、完整的项目结构

    |-- myproject
        |-- config.py
        |-- flask-env.yml
        |-- manage.py
        |-- app
        |   |-- models.py
        |   |-- __init__.py   # 创建app实例的工厂函数
        |   |-- auth  # auth蓝本
        |   |   |-- forms.py
        |   |   |-- views.py
        |   |   |-- __init__.py
        |   |   |-- templates
        |   |-- main   # main蓝本
        |   |   |-- errors.py
        |   |   |-- forms.py
        |   |   |-- views.py
        |   |   |-- __init__.py
        |   |-- static
        |   |   |-- css
        |   |   |-- image
        |   |   |-- js
        |   |-- templates
        |-- migrations
        |-- tests
        |   |-- __init__.py
        |-- venv
    

    五、动态配置类

    config.py

    
    import os
    basedir = os.path.abspath(os.path.dirname(__file__))
    
    
    # 通用配置
    class Config:
        WTF_CSRF_SECRET_KEY = os.environ.get('WTF_CSRF_SECRET_KEY') or 'ao blog csrf key'
        SECRET_KEY = os.environ.get('SECRET_KEY') or 'ao blog session key'
        SQLALCHEMY_COMMIT_ON_TEARDOWN = True
        SQLALCHEMY_TRACK_MODIFICATIONS = False
    
        # 初始化Flask实例,对当前环境的配置初始化
        @staticmethod
        def init_app(app):
            app.config['SECRET_KEY'] = SQLALCHEMY_COMMIT_ON_TEARDOWN
            app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = SQLALCHEMY_COMMIT_ON_TEARDOWN
            app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = SQLALCHEMY_COMMIT_ON_TEARDOWN
            app.config['WTF_CSRF_SECRET_KEY'] = SQLALCHEMY_COMMIT_ON_TEARDOWN
    
    
    # 开发环境配置
    class DevelopmentConfig(Config):
        DEBUG = True
        # SQLALCHEMY_TRACK_MODIF = True
        SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 
                                  'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
    
    
    class TestingConfig(Config):
        TESTING = True
        SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 
                                  'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
    
    class ProductionConfig(Config):
        SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 
                                  'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
    
    config = {
        'dev': DevelopmentConfig,
        'test': TestingConfig,
        'prod': ProductionConfig,
        'default': DevelopmentConfig
    }
    
    
  • 相关阅读:
    [Flink] 从 RabbitMQ 读取并计算后输出到 MySQL
    极光笔记丨搭建UMS私有云文件服务器
    极光笔记丨Spark SQL 在极光的建设实践
    Iog4j2漏洞相关技术分析
    极光笔记丨关于数据大屏一比一还原设计稿这件事
    极光笔记|基于CMPP协议集成短信测试桩全流程实践分享
    极光笔记|数据服务平台一期建设
    【记录】GIT常用命令
    【原创】使用micrel的千兆PHY芯片ksz9021GN和KSZ9021GQ前要注意
    【记录】调试千兆以太网PHY芯片DP83865的痛苦经历
  • 原文地址:https://www.cnblogs.com/yourblog/p/12683120.html
Copyright © 2020-2023  润新知