• day98:MoFang:服务端项目搭建


    目录

    1.准备工作

    2.创建项目启动文件manage.py

    3.构建全局初始化函数并在函数内创建app应用对象

    4.通过终端脚本启动项目

    5.项目加载配置

    6.数据库初始化

      1.SQLAlchemy初始化

      2.Redis初始化

      3.session存储到redis数据库中

      4.数据迁移初始化

    7.日志初始化

    8.蓝图初始化

      1.通过终端命令创建蓝图,并在蓝图中生成view/model/url等文件

      2.将蓝图注册到APP应用对象下

      3.注册路由和视图之间的关系

      4.自动注册蓝图下的所有模型

    1.准备工作

    1.新建项目目录mofangapi,并创建虚拟环境

    mkvirtualenv mofang

    2.安装开发中使用的依赖模块

    pip install flask==0.12.4
    pip install flask-redis
    pip install flask-session
    pip install flask-script
    pip install flask-mysqldb
    pip install flask-sqlalchemy
    pip install flask-migrate

    接下来,在pycharm中打开项目目录mofangapi编写manage.py启动项目的文件

    2.创建项目启动文件manage.py

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        app.run()

    manage.py终不能存放大量的开发代码, 在开发中应该体现的是一种分工精神,所以我们可以把flask中各种功能代码进行分类分文件存储.

    现在项目的目录结构如下所示:

    项目根目录/
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   ├ prod.py           # 生产阶段的配置文件
    |   |   ├ __init__.py       # 项目公共配置文件
    │   ├── __init__.py         # 项目初始化文件
    ├── manage.py               # 项目的终端管理脚本文件

    3.构建全局初始化函数并在函数内创建app应用对象

    1.把引导整个项目启动的全局初始化代码,保存到application/__init__py,代码:

    from flask import Flask
    
    def init_app():
        """全局初始化"""
        app = Flask(__name__) # 创建APP应用对象
        return app

    2.在manage.py,中调用初始化函数,创建app应用对象,代码:

    from application import init_app
    
    app = init_app() # 创建app应用对象
    
    @app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        app.run()

    4.通过终端脚本启动项目

    applicatiion/__init__py,代码:

    from flask import Flask
    from flask_script import Manager
    
    manager = Manager() # 引入终端脚本管理对象 ***
    
    def init_app():
        """全局初始化"""
        
        # 创建app应用对象
        app = Flask(__name__)
    
        # 初始化终端脚本工具 ***
        manager.app = app
    
        return manager

    manage.py的app改为manage,代码:

    from application import init_app
    
    manage = init_app()
    
    @manage.app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        manage.run()

    运行项目的方式就要修改如下:

    此时我们就可以通过如下指令去运行项目了

    python manage.py runserver -h0.0.0.0 -p5000

    5.项目加载配置

    1.在application/utils/config.py中准备加载配置的函数代码:

    from importlib import import_module
    def load_config(config_path):
        """自动加载配置"""
        module = import_module(config_path)
        name = config_path.split(".")[-1]
        if name == "settings":
            return module.InitConfig
        else:
            return module.Config

    2.编写项目默认配置文件, application/settings/__init__.py代码:

    class InitConfig():
        """项目默认初始化配置"""
        DEBUG = True

    当然, 项目开发过程完成以后肯定会项目上线,所以针对配置文件,我们可以准备不同环境下的配置

    application/settings/dev.py,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目开发环境下的配置"""
        DEBUG = True

    application/settings/prod.py,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目运营环境下的配置"""
        DEBUG = False

    3.在项目引导文件application/__init__py中加载配置,代码:

    from flask import Flask
    from flask_script import Manager
    from application.utils.config import load_config
    manager = Manager()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        
        # 设置项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        
        # 加载配置 ****
        Config = load_config(config_path) # 调用utils里自己已经写好的load_config方法
        app.config.from_object(Config) # 将配置类注册到APP上
    
        # 初始化终端脚本工具
        manager.app = app
    
        return manager

    4.在创建app对象的项目启动文件manage.py中,设置配置

    from application import init_app
    
    manage = init_app("application.settings.dev") # 设置默认项目使用的配置文件是dev.py
    
    @manage.app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        manage.run()

    6.数据库初始化

    1.SQLAlchemy初始化

    1.默认项目配置文件中增加配置选项,application/settings/__init__.py,代码:

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True

    2.开发配置dev.py中,配置数据库连接信息,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目开发环境下的配置"""
        DEBUG = True
        # 数据库
        SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
        SQLALCHEMY_ECHO = True

    3.在mysql终端下, 创建数据库用户,命令如下:

    create database mofang charset=utf8mb4;
    # 针对当前数据库配置账户信息
    create user mofang_user identified by 'mofang';
    grant all privileges on mofang.* to 'mofang_user'@'%';
    flush privileges;

    4.在项目全局引导文件中,对数据库功能进行初始化,application/__init__.py,代码:

    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from application.utils.config import load_config
    
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象 ***
    db = SQLAlchemy()
    
    def init_app(config_path):
        """全局初始化"""
        
        # 创建app应用对象
        app = Flask(__name__)
        # 项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化 ***
        db.init_app(app)
    
        # 初始化终端脚本工具
        manager.app = app
    
        return manager

    2.Redis初始化

    1.默认配置文件,application/settings/__init__py,代码:

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True
        # Redis
        REDIS_URL = "redis://@127.0.0.1:6379/0"

    2.在全局引导文件中, 对redis进行初始化,applicaiton/__init__.py,代码:

    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    
    from application.utils.config import load_config
    
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象 ***
    redis = FlaskRedis()
    
    def init_app(config_path):
        """全局初始化"""
    # 创建app应用对象 app = Flask(__name__) # 项目根目录 app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 加载配置 Config = load_config(config_path) app.config.from_object(Config) # 数据库初始化 db.init_app(app) redis.init_app(app) # redis数据库初始化 *** # 初始化终端脚本工具 manager.app = app return manager

    3.session存储到redis数据库中

    1.因为需要单独设置一个数据库存放session,所以我们再次单独配置一个关于session加载配置的函数init_session,

    application/utils/session.py,代码:

    from redis import Redis
    def init_session(app):
        host = app.config.get("SESSION_REDIS_HOST","127.0.0.1")
        port = app.config.get("SESSION_REDIS_PORT",6379)
        db = app.config.get("SESSION_REDIS_DB",0)
        print(db)
        app.config["SESSION_REDIS"] = Redis(host=host,port=port,db=db)

    2.默认配置文件application/settings/__init__.py中, 添加配置项:

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True
        # Redis
        REDIS_URL = ""
    
        # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串 ***
        SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"
    
        '''session存储配置''' ***
        # session存储方式配置 ***
        SESSION_TYPE = "redis"
        # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效 ***
        SESSION_PERMANENT = False
        # 设置session_id在浏览器中的cookie有效期 ***
        PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,单位是秒 ***
        # 是否对发送到浏览器上session的cookie值进行加密 ***
        SESSION_USE_SIGNER = True
        # 保存到redis的session数的名称前缀 ***
        SESSION_KEY_PREFIX = "session:"
        # session保存数据到redis时启用的链接对象 ***
        SESSION_REDIS = None   # 用于连接redis的配置 ***
    
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 0

    3.在本地开发配置中,设置session存储指定的redis库中,application/settings/dev.py,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目开发环境下的配置"""
        DEBUG = True
        # 数据库
        SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
        SQLALCHEMY_ECHO = True
    
        # redis ***
        REDIS_URL = "redis://@127.0.0.1:6379/0" # 0号redis库用来存redis缓存
    
        # session存储配置 ***
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1 # 1号redis库用来存session

    4.在项目全局引导文件application/__init__.py中对session存储进行初始化,代码:

    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    from flask_session import Session
    
    from application.utils.config import load_config
    from application.utils.session import init_session
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象
    redis = FlaskRedis()
    
    # Session存储对象 ***
    session_store = Session()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        # 项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化
        db.init_app(app)
        redis.init_app(app)
    
        # session存储初始化 ***
        init_session(app) # 加载session配置 
        session_store.init_app(app) # session存储初始化
        
        # 初始化终端脚本工具
        manager.app = app
    
        return manager

    4.数据迁移初始化

    1.项目全局引导文件application/__init__py,代码:

    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    from flask_session import Session
    from flask_migrate import Migrate,MigrateCommand # ***
    
    from application.utils.config import load_config
    from application.utils.session import init_session
    
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象
    redis = FlaskRedis()
    
    # Session存储对象
    session_store = Session()
    
    # 数据迁移实例对象 ***
    migrate = Migrate()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        # 项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化 
        db.init_app(app)
        redis.init_app(app)
    
        # session存储初始化
        init_session(app)
        session_store.init_app(app)
    
        # 数据迁移初始化 ***
        migrate.init_app(app,db)
        # 添加数据迁移的命令到终端脚本工具中 ***
        manager.add_command('db', MigrateCommand)
    
        # 初始化终端脚本工具
        manager.app = app
    
        return manager

    完成上面的项目构建步骤以后,此时目录结构如下:

    项目根目录/
    ├── docs/                   # 项目开发文档/接口等备份资料存储目录
    ├── logs/                   # 项目日志存储目录
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   ├ prod.py           # 生产阶段的配置文件
    |   |   ├ __init__.py       # 项目公共配置文件
    |   ├── utils/              # 工具函数库/类库
    │   │   ├ session.py        # session相关的辅助函数
    │   │   ├ config.py         # 配置相关的辅助函数
    │   ├── __init__.py         # 项目初始化文件
    └── manage.py               # 项目的终端管理脚本文件

    7.日志初始化

    flask中没有内置的日志功能,我们在使用的时候, 一般日志如果不是核心重点,则通过由python内置的logging模块进行配置集成使用即可, 如果项目中日志发挥作用比较重要, 则一般安装部署 ELK日志分析系统.

    1.日志的等级

    FATAL/CRITICAL = 致命的,危险的
    ERROR = 错误
    WARNING = 警告
    INFO = 信息
    DEBUG = 调试

    2.构建日志模块

    1.把日志初始化相关的代码封装成一个函数,application/utils/logger.py,代码:

    import logging
    from logging.handlers import RotatingFileHandler
    
    class Log():
        """日志模块"""
        
        def __init__(self, app=None):
            if app is not None:
                self.init_app(app)
    
        def init_app(self,app):
            self.app = app
            return self.setup()
    
        def setup(self):
            """安装日志功能到flask中"""
            # 设置日志的记录等级
            logging.basicConfig(level=self.app.config.get("LOG_LEVEL"))  # 调试debug级
    
            # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
            file_log_handler = RotatingFileHandler(
                self.app.BASE_DIR+self.app.config.get("LOG_DIR"),
                maxBytes=self.app.config.get("LOG_MAX_BYTES"),
                backupCount=self.app.config.get("LOG_BACKPU_COUNT")
            )
    
            # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
            formatter = logging.Formatter('%(name)s: %(levelname)s %(asctime)s %(filename)s:%(lineno)d %(message)s')
            # 为刚创建的日志记录器设置日志记录格式
            file_log_handler.setFormatter(formatter)
    
            # 为全局的日志工具对象(flaskapp使用的)添加日志记录器
            logging.getLogger(self.app.config.get("LOG_NAME")).addHandler(file_log_handler)
            # 返回日志器对象提供给业务开发
            logger = logging.getLogger(self.app.config.get("LOG_NAME"))
            return logger

    2.application/settings/__init__.py代码:

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True
        # Redis
        REDIS_URL = ""
    
        # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
        SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"
    
        # session存储配置
        # session存储方式配置
        SESSION_TYPE = "redis"
        # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效
        SESSION_PERMANENT = False
        # 设置session_id在浏览器中的cookie有效期
        PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,单位是秒
        # 是否对发送到浏览器上session的cookie值进行加密
        SESSION_USE_SIGNER = True
        # 保存到redis的session数的名称前缀
        SESSION_KEY_PREFIX = "session:"
        # session保存数据到redis时启用的链接对象
        SESSION_REDIS = None   # 用于连接redis的配置
    
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1
    
        # 调整json数据转换中文的配置
        JSON_AS_ASCII=False
    
        # 日志相关配置 ***
        LOG_LEVEL        = "INFO"              # 日志输出到文件中的最低等级
        LOG_DIR          = "logs/0.log"        # 日志存储目录
        LOG_MAX_BYTES    = 300 * 1024 * 1024   # 单个日志文件的存储上限[单位: b]
        LOG_BACKPU_COUNT = 20                  # 日志文件的最大备份数量
        LOG_NAME         = "flask"             # 日志器的名字

    3.开发环境配置文件dev.py中配置具体的日志相关信息,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目开发环境下的配置"""
        DEBUG = True
        # 数据库
        SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
        SQLALCHEMY_ECHO = True
    
        # redis
        REDIS_URL = "redis://@127.0.0.1:6379/0"
    
        # session存储配置
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1
    
        # 日志配置 ***
        LOG_LEVEL        = "DEBUG"             # 日志输出到文件中的最低等级
        LOG_DIR          = "/logs/mofang.log"  # 日志存储目录
        LOG_MAX_BYTES    = 300 * 1024 * 1024   # 单个日志文件的存储上限[单位: b]
        LOG_BACKPU_COUNT = 20                  # 日志文件的最大备份数量
        LOG_NAME = "mofang"                    # 日志器名称

    4.在 application/__init__.py文件中的init_app 方法中调用日志初始化。

    import os,logging
    
    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    from flask_session import Session
    from flask_migrate import Migrate,MigrateCommand
    
    from application.utils.config import load_config
    from application.utils.session import init_session
    from application.utils.logger import Log
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象
    redis = FlaskRedis()
    
    # Session存储对象
    session_store = Session()
    
    # 数据迁移实例对象
    migrate = Migrate()
    
    # 日志对象 ***
    log = Log()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化
        db.init_app(app)
        redis.init_app(app)
    
        # session存储初始化
        init_session(app)
        session_store.init_app(app)
    
        # 数据迁移初始化
        migrate.init_app(app,db)
        # 添加数据迁移的命令到终端脚本工具中
        manager.add_command('db', MigrateCommand)
    
        # 日志初始化 ***
        app.log = log.init_app(app)
    
        # 初始化终端脚本工具
        manager.app = app
    
        return manager

    新增日志的项目目录结构如下所示

    ├── application
    │   ├── __init__.py
    │   ├── settings
    │   │   ├── dev.py
    │   │   ├── __init__.py
    │   │   ├── prod.py
    │   └── utils
    │       ├── config.py
    │       ├── __init__.py
    │       ├── logger.py      # 日志相关模块代码库
    │       └── session.py
    ├── docs
    ├── logs                    # 日志文件存储目录
    │   └── mofang.log
    └── manage.py

    经过上面的改造,我们接下来就可以开始创建蓝图了。

    8.蓝图初始化

    1.通过终端命令创建蓝图,并在蓝图中生成view/model/url等文件

    1.在application下创建apps目录,apps以后专门用于保存每一个项目的蓝图,并在apps创建home蓝图目录,并在__init__.py文件中创建蓝图对象

    通过自定义终端命令, 创建一个自动生成蓝图目录的命令.application/utils/commands.py,代码:

    from flask_script import Command, Option
    
    class BlueprintCommand(Command):
        """蓝图生成命令"""
        name = "blue"
        option_list = [
            Option('--name', '-n', dest='name'),
        ]
        def run(self, name):
            # 生成蓝图名称对象的目录
            os.mkdir(name)
            open("%s/__init__.py" % name, "w")
            open("%s/views.py" % name, "w")
            open("%s/models.py" % name, "w")
            with open("%s/urls.py" % name, "w") as f:
                content = """from . import views
    from application.utils import path
    urlpatterns = [
    
    ]"""
                f.write(content)
            print("蓝图%s创建完成...." % name)

    2.上面的命令就可以帮我们完成项目中生成蓝图的功能,接下来我们就可以直接把命令注册到manage对象中就可以使用了.

    但是, 我们往后的开发中肯定还会继续的需要进行自定义终端命令,所以我们声明一个load_command的函数,让自动帮我们完成加载注册自定义终端命令的过程.

    application/utils/commands.py,代码:

     

    import os
    from importlib import import_module
    from flask_script import Command, Option
    import inspect
    
    def load_command(manager,command_path=None):
        """自动加载自定义终端命令"""
        if command_path is None:
            command_path = "application.utils.commands"
    
        module = import_module(command_path)
        class_list = inspect.getmembers(module,inspect.isclass)
        for class_item in class_list:
            if issubclass(class_item[1],Command) and class_item[0] != "Command":
                manager.add_command(class_item[1].name,class_item[1])
    
    class BlueprintCommand(Command):
        """蓝图生成命令"""
        name = "blue"
        option_list = [
            Option('--name', '-n', dest='name'),
        ]
        def run(self, name):
            # 生成蓝图名称对象的目录
            os.mkdir(name)
            open("%s/__init__.py" % name, "w")
            open("%s/views.py" % name, "w")
            open("%s/models.py" % name, "w")
            with open("%s/urls.py" % name, "w") as f:
                content = """from . import views
    from application.utils import path
    urlpatterns = [
    
    ]"""
                f.write(content)
            print("蓝图%s创建完成...." % name)

    3.在项目全局引导文件application/__init__.py中, 调用load_command函数注册命令

    import os,logging
    
    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    from flask_session import Session
    from flask_migrate import Migrate,MigrateCommand
    
    from application.utils.config import load_config
    from application.utils.session import init_session
    from application.utils.logger import Log
    from application.utils.commands import load_command
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象
    redis = FlaskRedis()
    
    # Session存储对象
    session_store = Session()
    
    # 数据迁移实例对象
    migrate = Migrate()
    
    # 日志对象
    log = Log()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化
        db.init_app(app)
        redis.init_app(app)
    
        # session存储初始化
        init_session(app)
        session_store.init_app(app)
    
        # 数据迁移初始化
        migrate.init_app(app,db)
        # 添加数据迁移的命令到终端脚本工具中
        manager.add_command('db', MigrateCommand)
    
        # 日志初始化
        app.log = log.init_app(app)
    
        # 初始化终端脚本工具
        manager.app = app
    
        # 注册自定义命令 ***
        load_command(manager)
    
        return manager

    4.接下来就可以在终端下,通过命令生成蓝图目录了.

    命令:

    cd application/apps
    python ../../manage.py blue -nhome

    效果:

    2.将蓝图注册到APP应用对象下

    有了蓝图以后,接下来我们就可以视图代码,模型代码,路由代码等存储到蓝图目录下了,但是我们需要把蓝图注册到app应用对象下.所以我们注册蓝图这块代码也可以封装到一个函数中.让程序自动识别并注册.

    项目中可以有多个蓝图,但是有些蓝图可能并不能提供给客户端访问,所以我们需要在配置文件中声明一个蓝图注册列表, 在init_blueprint函数中只注册配置列表的蓝图

    1.application/settings/__init__.py,代码:

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True
        # Redis
        REDIS_URL = ""
    
        # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
        SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"
    
        # session存储配置
        # session存储方式配置
        SESSION_TYPE = "redis"
        # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效
        SESSION_PERMANENT = False
        # 设置session_id在浏览器中的cookie有效期
        PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,单位是秒
        # 是否对发送到浏览器上session的cookie值进行加密
        SESSION_USE_SIGNER = True
        # 保存到redis的session数的名称前缀
        SESSION_KEY_PREFIX = "session:"
        # session保存数据到redis时启用的链接对象
        SESSION_REDIS = None   # 用于连接redis的配置
    
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1
    
        # 调整json数据转换中文的配置
        JSON_AS_ASCII=False
    
        # 日志相关配置
        LOG_LEVEL        = "INFO"              # 日志输出到文件中的最低等级
        LOG_DIR          = "logs/0.log"        # 日志存储目录
        LOG_MAX_BYTES    = 300 * 1024 * 1024   # 单个日志文件的存储上限[单位: b]
        LOG_BACKPU_COUNT = 20                  # 日志文件的最大备份数量
        LOG_NAME         = "flask"             # 日志器的名字
    
        # 蓝图注册列表 ***
        INSTALLED_APPS = [
    
        ]

    application/settings/dev.py,代码:

    from . import InitConfig
    class Config(InitConfig):
        """项目开发环境下的配置"""
        DEBUG = True
        # 数据库
        SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
        SQLALCHEMY_ECHO = True
    
        # redis
        REDIS_URL = "redis://@127.0.0.1:6379/0"
    
        # session存储配置
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1
    
        # 日志配置
        LOG_LEVEL        = "DEBUG"             # 日志输出到文件中的最低等级
        LOG_DIR          = "/logs/mofang.log"  # 日志存储目录
        LOG_MAX_BYTES    = 300 * 1024 * 1024   # 单个日志文件的存储上限[单位: b]
        LOG_BACKPU_COUNT = 20                  # 日志文件的最大备份数量
        LOG_NAME = "mofang"                    # 日志器名称
    
        # 注册蓝图  ***
        INSTALLED_APPS = [ 
            "application.apps.home",
        ]

    2.在init_blueprint函数中,针对注册的蓝图列表注册到app应用对象里面,

    application/utils/__init__.py,代码:

    def init_blueprint(app):
        """自动注册蓝图"""
        blueprint_path_list = app.config.get("INSTALLED_APPS")
        for blueprint_path in blueprint_path_list:
            blueprint_name = blueprint_path.split(".")[-1]
            # 自动创建蓝图对象
            blueprint = Blueprint(blueprint_name,blueprint_path)
    
            # 注册蓝图对象到app应用对象中
            app.register_blueprint(blueprint,url_prefix="")

    3.项目全局引导文件中, 调用init_blueprint方法, 自动注册蓝图.application/__init__.py,代码:

    import os,logging
    
    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from flask_redis import FlaskRedis
    from flask_session import Session
    from flask_migrate import Migrate,MigrateCommand
    
    from application.utils import init_blueprint
    from application.utils.config import load_config
    from application.utils.session import init_session
    from application.utils.logger import Log
    from application.utils.commands import load_command
    # 创建终端脚本管理对象
    manager = Manager()
    
    # 创建数据库链接对象
    db = SQLAlchemy()
    
    # redis链接对象
    redis = FlaskRedis()
    
    # Session存储对象
    session_store = Session()
    
    # 数据迁移实例对象
    migrate = Migrate()
    
    # 日志对象
    log = Log()
    
    def init_app(config_path):
        """全局初始化"""
        # 创建app应用对象
        app = Flask(__name__)
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 加载配置
        Config = load_config(config_path)
        app.config.from_object(Config)
    
        # 数据库初始化
        db.init_app(app)
        redis.init_app(app)
    
        # session存储初始化
        init_session(app)
        session_store.init_app(app)
    
        # 数据迁移初始化
        migrate.init_app(app,db)
        # 添加数据迁移的命令到终端脚本工具中
        manager.add_command('db', MigrateCommand)
    
        # 日志初始化
        app.log = log.init_app(app)
    
        # 蓝图注册 ***
        init_blueprint(app)
    
        # 初始化终端脚本工具
        manager.app = app
    
        # 注册自定义命令
        load_command(manager)
    
        return manager

    3.注册路由和视图之间的关系

    1.注册子路由和视图之间的关系

    注册了蓝图对象以后,蓝图下面的视图方法和视图对应的路由关系也要进行注册!

    所以, 在蓝图home下面的urls.py文件中,通过path方法把url地址和视图方法进行处理成字典,然后把字典作为成员返回到变量urlpatterns列表中.

    1.application/utils/__init__.py,生成path函数,代码:

    from flask import Blueprint
    from importlib import import_module
    def path(rule,func_view):
        # 把蓝图下视图和路由之间的映射关系处理成字典结构,方便后面注册蓝图的时候,直接传参
        return {"rule":rule,"view_func":func_view}

    2.在蓝图下的urls.py中,注册视图和路由的关系,home/urls.py,代码:

    from . import views
    from application.utils import path
    urlpatterns = [
        path("/",views.index),
    ]

    视图代码:

    def index():
        return 'index'

    3.在init_blueprint初始化蓝图的函数中, 生成蓝图对象以后自动加载并注册蓝图和视图

    application/utils/__init__.py,代码:

    from flask import Blueprint
    from importlib import import_module
    def path(rule,func_view):
        # 把蓝图下视图和路由之间的映射关系处理成字典结构,方便后面注册蓝图的时候,直接传参
        return {"rule":rule,"view_func":func_view}
    
    def init_blueprint(app):
        """自动注册蓝图"""
        blueprint_path_list = app.config.get("INSTALLED_APPS")
        for blueprint_path in blueprint_path_list:
            blueprint_name = blueprint_path.split(".")[-1]
            # 自动创建蓝图对象
            blueprint = Blueprint(blueprint_name,blueprint_path)
            # 蓝图自动注册和绑定视图和子路由
            url_module = import_module(blueprint_path+".urls") # 加载蓝图下的子路由文件
            for url in url_module.urlpatterns: # 遍历子路由中的所有路由关系
                blueprint.add_url_rule(**url)  # 注册到蓝图下
            # 注册蓝图对象到app应用对象中
            app.register_blueprint(blueprint,url_prefix="")

    2.注册总路由和蓝图之间的关系

    4.此时, 运行项目,就允许蓝图中视图通过url地址提供给客户端访问了.

    上面蓝图注册到app时, 没有设置url_prefix路由前缀, 接下来我们可以单独设置一个总路由application/urls.py,进行路由前缀的设置.

    在项目默认配置文件中,application/settings/__init__.py,新增总路由的配置项

    class InitConfig():
        """项目默认初始化配置"""
        # 调试模式
        DEBUG = True
    
        # 数据库相关配置
        SQLALCHEMY_DATABASE_URI = ""
        # 动态追踪修改设置
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True
        # Redis
        REDIS_URL = ""
    
        # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
        SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"
    
        # session存储配置
        # session存储方式配置
        SESSION_TYPE = "redis"
        # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效
        SESSION_PERMANENT = False
        # 设置session_id在浏览器中的cookie有效期
        PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,单位是秒
        # 是否对发送到浏览器上session的cookie值进行加密
        SESSION_USE_SIGNER = True
        # 保存到redis的session数的名称前缀
        SESSION_KEY_PREFIX = "session:"
        # session保存数据到redis时启用的链接对象
        SESSION_REDIS = None   # 用于连接redis的配置
    
        SESSION_REDIS_HOST = "127.0.0.1"
        SESSION_REDIS_PORT = 6379
        SESSION_REDIS_DB = 1
    
        # 调整json数据转换中文的配置
        JSON_AS_ASCII=False
    
        # 日志相关配置
        LOG_LEVEL        = "INFO"              # 日志输出到文件中的最低等级
        LOG_DIR          = "logs/0.log"        # 日志存储目录
        LOG_MAX_BYTES    = 300 * 1024 * 1024   # 单个日志文件的存储上限[单位: b]
        LOG_BACKPU_COUNT = 20                  # 日志文件的最大备份数量
        LOG_NAME         = "flask"             # 日志器的名字
    
        # 蓝图注册列表
        INSTALLED_APPS = [
    
        ]
    
    
        # 总路由 ***
        URL_PATH = "application.urls"

    5.创建总路由文件并注册蓝图和路由前缀的关系, application/urls.py,代码:

    from application.utils import include
    urlpatterns = [
        include("","home.urls"),
    ]

    6.接下来,在init_blueprint蓝图初始化函数中新增判断识别路由前缀的代码; 同时, 把路由前缀和蓝图映射关系的处理代码封装成include方法,方便以后需求变化时可以直接调整.

    application/utils/__init__.py,代码:

    from flask import Blueprint
    from importlib import import_module
    def path(rule,func_view):
        # 把蓝图下视图和路由之间的映射关系处理成字典结构,方便后面注册蓝图的时候,直接传参
        return {"rule":rule,"view_func":func_view}
    
    def include(url_prefix, blueprint_path):
        """把路由前缀和蓝图进行关系映射"""
        return {"url_prefix":url_prefix,"blueprint_path":blueprint_path}
    
    def init_blueprint(app):
        """自动注册蓝图"""
        blueprint_path_list = app.config.get("INSTALLED_APPS")
        for blueprint_path in blueprint_path_list:
            blueprint_name = blueprint_path.split(".")[-1]
            # 自动创建蓝图对象
            blueprint = Blueprint(blueprint_name,blueprint_path)
            # 蓝图自动注册和绑定视图和子路由
            url_module = import_module(blueprint_path+".urls") # 加载蓝图下的子路由文件
            for url in url_module.urlpatterns: # 遍历子路由中的所有路由关系
                blueprint.add_url_rule(**url)  # 注册到蓝图下
    
            # 读取总路由文件
            url_path = app.config.get("URL_PATH")
            urlpatterns = import_module(url_path).urlpatterns  # 加载蓝图下的子路由文件
            url_prefix = "" # 蓝图路由前缀
            for urlpattern in urlpatterns:
                if urlpattern["blueprint_path"] == blueprint_name+".urls":
                    url_prefix = urlpattern["url_prefix"]
                    break
            # 注册蓝图对象到app应用对象中,  url_prefix 蓝图的路由前缀
            app.register_blueprint(blueprint,url_prefix=url_prefix)

    4.自动注册蓝图下的所有模型

    1.在蓝图下的models.py中声明模型,例如:

    from application import db
    class User(db.Model):
        __tablename__ = "mf_user"
        id = db.Column(db.Integer, primary_key=True, comment="主键ID")
        name = db.Column(db.String(255), unique=True, comment="账户名")
        password = db.Column(db.String(255), comment="登录密码")
        ip_address = db.Column(db.String(255), index=True, comment="登录IP")
    
        def __repr__(self):
            return self.name

    2.然后在终端下执行数据迁移

    cd ../..
    python manage.py db init
    python manage.py db migrate -m "text"

    3.上面的命令执行以后, 我们可以发现模型根本被flask进行识别到.所以我们需要把模型注册到flask项目中.

    application/utils/__init__.py,代码:

    from flask import Blueprint
    from importlib import import_module
    def path(rule,func_view):
        # 把蓝图下视图和路由之间的映射关系处理成字典结构,方便后面注册蓝图的时候,直接传参
        return {"rule":rule,"view_func":func_view}
    
    def include(url_prefix, blueprint_path):
        """把路由前缀和蓝图进行关系映射"""
        return {"url_prefix":url_prefix,"blueprint_path":blueprint_path}
    
    def init_blueprint(app):
        """自动注册蓝图"""
        blueprint_path_list = app.config.get("INSTALLED_APPS")
        for blueprint_path in blueprint_path_list:
            blueprint_name = blueprint_path.split(".")[-1]
            # 自动创建蓝图对象
            blueprint = Blueprint(blueprint_name,blueprint_path)
            # 蓝图自动注册和绑定视图和子路由
            url_module = import_module(blueprint_path+".urls") # 加载蓝图下的子路由文件
            for url in url_module.urlpatterns: # 遍历子路由中的所有路由关系
                blueprint.add_url_rule(**url)  # 注册到蓝图下
    
            # 读取总路由文件
            url_path = app.config.get("URL_PATH")
            urlpatterns = import_module(url_path).urlpatterns  # 加载蓝图下的子路由文件
            url_prefix = "" # 蓝图路由前缀
            for urlpattern in urlpatterns:
                if urlpattern["blueprint_path"] == blueprint_name+".urls":
                    url_prefix = urlpattern["url_prefix"]
                    break
    
            # 注册模型 ***
            import_module(blueprint_path+".models")
    
            # 注册蓝图对象到app应用对象中,  url_prefix 蓝图的路由前缀
            app.register_blueprint(blueprint,url_prefix=url_prefix)

    项目能自动加载总路由和蓝图路由以后的项目目录结构,如下:

    项目根目录/
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ __init__.py       # 项目默认初始化配置文件
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   └ prod.py           # 生产阶段的配置文件
    │   ├── __init__.py         # 项目初始化全局引导文件
    |   ├── utils/              # 项目工具类库目录
    │   │   ├ commands.py       # 自定义命令和加载命令的相关函数
    │   │   ├ config.py         # 项目配置加载的辅助函数
    │   │   ├ session.py        # 项目存储session相关的函数
    │   │   └ logger.py         # 日志模块
    │   ├── apps/               # 保存项目中所有蓝图的存储目录
    │   │   ├── home            # 蓝图目录【这里是举例而已】
    │   │   │   ├── __init__.py # 蓝图的初始化文件
    │   │   │   ├── urls.py     # 蓝图的子路由文件
    │   │   │   ├── models.py   # 蓝图的模型文件
    │   │   │   └── views.py    # 蓝图的视图文件
    │   │   ├── __init__.py
    │   └── urls.py              # 总路由
    ├── manage.py               # 项目的终端管理脚本文件
  • 相关阅读:
    #Leetcode# 541. Reverse String II
    PAT 甲级 1030 Travel Plan
    PAT 甲级 1029 Median
    bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊
    jzoj 4243. 【五校联考6day1】c
    2019.02.23【NOIP提高组】模拟 A 组 总结
    【GDOI2013模拟1】病毒传播
    【GDOI2013模拟1】最短路
    【GDOI2013模拟1】删数字
    数列分块入门 6 总结
  • 原文地址:https://www.cnblogs.com/libolun/p/14045041.html
Copyright © 2020-2023  润新知