zoukankan      html  css  js  c++  java
  • 4. 魔方服务端项目搭建

    魔方服务端项目搭建

    创建虚拟环境

    # 创建mofang虚拟环境
    conda create -n mofang python=3.8.5
    

    安装依赖

    pip install flask==1.1.4 -i https://pypi.douban.com/simple
    pip install flask-redis -i https://pypi.douban.com/simple
    pip install flask-session -i https://pypi.douban.com/simple
    pip install flask-script -i https://pypi.douban.com/simple
    pip install flask-mysqldb -i https://pypi.douban.com/simple
    pip install flask-sqlalchemy -i https://pypi.douban.com/simple
    

    创建项目目录结构 - 1

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

    在pycharm中打开项目目录mofangapi, settings中配置mofang虚拟环境, 编写manage.py启动项目的文件

    manage.py

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

    构建全局初始化函数创建app应用对象

    全局初始化文件application/__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调用初始化函数

    from application import init_app
    
    # 引入终端命令实例化Manager对象
    manager = init_app()
    app = manager.app  # flask的实例化对象
    
    @app.route('/')
    def index():
        return 'hello!!'
    
    if __name__ == '__main__':
        manager.run()
    

    项目运行

    1. 终端命令运行:
    python manage.py runserver 
    python manage.py runserver -d  # 进入调试模式
    python manage.py runserver -h0.0.0.0 -p5000
    python manage.py runserver -h0 -p5000
    
    1. 编辑,使用manage文件运行:
    pycharm右上角运行标识左边下拉框manage,点击 -> Edit Configurations.. ->Paramets中添加:
    	- runserver -h0 -p5000  
    

    项目加载配置

    1. 编写项目默认配置文件, application/settings/__init__.py代码:
    """公共配置"""
    # 调试模式
    DEBUG = True
    

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

    1. 开发环境配置application/settings/dev.py
    """开发环境配置"""
    
    # 调试模式
    DEBUG = True
    
    1. 线上生产环境配置application/settings/prod.py
    """线上生产环境配置"""
    
    # 调试模式
    DEBUG = False
    
    1. application/utils/config.py中准备加载配置的函数代码:
    """加载配置"""
    
    def init_config(app, config_path):
        """
        先加载默认配置,然后加载当前指定配置
        主要看传入的config_path:
            - 1.config_path = application.settings.dev
                - 加载开发环境配置
                - settings/__init__公共配置
            - 2.config_path = application.settings.prod
                - 加载线上生产环境配置
                - settings/__init__公共配置
        """
        init_path = ".".join(config_path.split('.')[:-1])
        app.config.from_object(init_path)  # 加载公共配置
        app.config.from_object(config_path) # 加载开发或生产配置
    
    1. 全局初始化文件application/__init__.py 中加载配置:
    from flask import Flask
    from flask_script import Manager
    from application.utils.config import init_config
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # 终端脚本工具加载配置
        manager.app = app
    
        return manager
    
    1. 主文件manage.py中, 实例化对象时设置配置
    from application import init_app
    
    # 开发环境配置路径
    config_path = 'application.settings.dev'
    
    # 引入终端命令实例化对象
    manager = init_app(config_path)
    app = manager.app
    
    @app.route('/')
    def index():
        return 'hello!!'
    
    if __name__ == '__main__':
        manager.run()
    

    数据库初始化

    1. SQLAlchemy初始化

    1. 默认项目配置文件中增加配置选项application/settings/__init__.py
    """公共配置"""
    
    """调试模式"""
    DEBUG = True
    
    """SQLAlchem数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = ''
    # 动态追踪修改设置
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = False
    
    
    1. 在mysql终端下, 创建属于当前项目的数据库管理用户, 命令如下:
    # 创建项目使用的数据库
    create database mofang charset=utf8mb4;
    
    # 针对项目数据库配置账户信息,创建用户并赋予权限
    
    # mysql8.0之前
    create user mofanguser identified by 'mofang'; 
    grant all privileges on mofang.* to 'mofanguser'@'%';
    flush privileges;
    
    # mysql8.0之后
    create user 'mofanguser'@'%' identified with mysql_native_password by 'mofang';
    GRANT ALL ON mofang.* TO 'mofanguser'@'%';
    
    1. 开发配置文件application/settings/dev.py中,配置数据库连接信息
    """开发环境配置"""
    
    # 调试模式
    DEBUG = True
    
    """SQLAlchemy数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = 'mysql://mofanguser:mofang@127.0.0.1:3306/mofang?charset=utf8mb4'
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = True
    
    1. 在项目全局引导文件中,对数据库功能进行初始化,application/__init__.py
    from flask import Flask
    from flask_script import Manager
    from flask_sqlalchemy import SQLAlchemy
    from application.utils.config import init_config
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # 终端脚本工具加载配置
        manager.app = app
    
        return manager
    

    2. Redis数据库初始化

    1. 默认配置文件,application/settings/__init__py,代码:
    """公共配置"""
    
    """调试模式"""
    DEBUG = True
    
    """SQLAlchem数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = ''
    # 动态追踪修改设置
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = False
    
    """redis数据库配置"""
    # 默认缓存数据库 - 0号库
    REDIS_URL = 'redis://:@127.0.0.1:6379/0'
    
    1. 开发环境配置文件,application/settings/dev.py,代码:
    """开发环境配置"""
    
    # 调试模式
    DEBUG = True
    
    """SQLAlchemy数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = 'mysql://mofanguser:mofang@127.0.0.1:3306/mofang?charset=utf8mb4'
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = True
    
    """redis数据库配置"""
    # 默认缓存数据库 - 0号库
    REDIS_URL = 'redis://:@127.0.0.1:6379/0'
    # 验证相关数据 - 1号库
    CHECK_URL = 'redis://:@127.0.0.1:6379/1'
    
    1. 在全局引导文件中, 对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 init_config
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
    
        # 终端脚本工具加载配置
        manager.app = app
    
        return manager
    

    3. 配置Session存储到redis数据库中

    1. 默认配置文件设置SECRET_KEY秘钥, application/settings/__init__.py
    """公共配置"""
    
    """调试模式"""
    DEBUG = True
    
    """设置加密秘钥"""
    # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
    SECRET_KEY = "RvDsY4u6GRJm4srpe2NUbpxS3R8+5yZRNTcYkx7NtzHpumOK4Wq/+f+qplfxgGld"
    
    """SQLAlchem数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = ''
    # 动态追踪修改设置
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = False
    
    """redis数据库配置"""
    # 默认缓存数据库 - 0号库
    REDIS_URL = 'redis://:@127.0.0.1:6379/0'
    
    1. 开发环境配置文件中.配置session储存的redis数据库 , application/settings/dev.py
    """开发环境配置"""
    
    # 调试模式
    DEBUG = True
    
    """SQLAlchemy数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = 'mysql://mofanguser:mofang@127.0.0.1:3306/mofang?charset=utf8mb4'
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = True
    
    """redis数据库配置"""
    # 默认缓存数据库 - 0号库
    REDIS_URL = 'redis://:@127.0.0.1:6379/0'
    # 验证相关数据 - 1号库
    CHECK_URL = 'redis://:@127.0.0.1:6379/1'
    # session储存数据库 - 2号库
    SESSION_URL = 'redis://:@127.0.0.1:6379/2'
    
    """session数据储存到Redis的配置"""
    # 配置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:"
    
    
    1. 全局引导文件中, 初始化redis数据库, 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 application.utils.config import init_config
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    # - 3.验证相关数据库对象,配置前缀为SESSION
    redis_session = FlaskRedis(config_prefix='SESSION')
    
    # session储存配置初始化
    session_store = Session()
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
        redis_session.init_app(app)
    
        """一定先加载默认配置,再传入APP加载session对象"""
        # session保存数据到redis时启用的链接对象
        app.config["SESSION_REDIS"] = redis_session
        # session存储对象加载配置
        session_store.init_app(app)
    
    
        # 终端脚本工具加载配置
        manager.app = app
    
        return manager
    

    日志初始化

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

    日志的等级

    从高到低,依次:
    	FATAL/CRITICAL = 致命的,危险的
    	ERROR = 错误
    	WARNING = 警告
    	INFO = 信息
    	DEBUG = 调试
    

    flask日志功能的基本使用

    app.logger.fatal("致命")    # [2021-05-28 17:44:08,524] CRITICAL in manage: 致命
    app.logger.error("错误")    # [2021-05-28 17:42:41,597] ERROR in manage: 错误
    app.logger.warning("警告")  # [2021-05-28 17:43:34,401] WARNING in manage: 警告
    
    # debug模式关闭了以后,info和debug等级的日志记录不会输出了
    app.logger.info("运行信息")  # [2021-05-28 17:44:39,914] INFO in manage: 运行信息
    app.logger.debug("调试信息") # [2021-05-28 17:45:01,131] DEBUG in manage: 调试信息
    

    在项目运行时,框架本身会不断记录代码程序运行的日志错误,我们在这里新建一个日志记录器,专门只是记录我们业务逻辑的相关日志。

    构建日志模块

    1. 开发环境配置文件写入日志的基本信息, application/settings/dev.py
    """开发环境配置"""
    
    # 调试模式
    DEBUG = True
    
    """SQLAlchemy数据库配置"""
    # 数据库链接
    SQLALCHEMY_DATABASE_URI = 'mysql://mofanguser:mofang@127.0.0.1:3306/mofang?charset=utf8mb4'
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = True
    
    """redis数据库配置"""
    # 默认缓存数据库 - 0号库
    REDIS_URL = 'redis://:@127.0.0.1:6379/0'
    # 验证相关数据 - 1号库
    CHECK_URL = 'redis://:@127.0.0.1:6379/1'
    # session储存数据库 - 2号库
    SESSION_URL = 'redis://:@127.0.0.1:6379/2'
    
    """session数据储存到Redis的配置"""
    # 配置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:"
    
    """日志基本信息配置"""
    LOG_LEVEL = 'INFO'              # 日志输出到文件中的等级
    LOG_DIR = '/logs/mofang.log'    # 日志存储路径
    LOG_BACKPU_COUNT = 20           # 日志文件的最大备份数量
    LOG_NAME = 'mofang'             # 日志器的名字,flask的名为:flask.app
    
    1. 把日志初始化相关的代码封装成一个日志类,application/utils/logger.py
    """日志模块配置"""
    import logging
    from logging.handlers import TimedRotatingFileHandler
    
    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'))
    
            # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
            file_log_handler = TimedRotatingFileHandler(
                filename=self.app.BASE_DIR + self.app.config.get('LOG_DIR'),
                when='midnight',# 每天新增日志的时间,午夜
                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"))
            # 给flask默认的日志记录器增加写入日志到logs
            self.app.logger.addHandler(file_log_handler)
    
            return logger
    
    1. 在项目引入文件加载初始化日志配置, application/__init__.py
    import os
    
    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 init_config
    from application.utils.logger import Log
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    # - 3.验证相关数据库对象,配置前缀为SESSION
    redis_session = FlaskRedis(config_prefix='SESSION')
    
    # session储存配置初始化
    session_store = Session()
    
    # 自定义日志初始化
    logger = Log()
    
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 当前项目根目录 - 日志加载配置时需要
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
        redis_session.init_app(app)
    
        """一定先加载默认配置,再传入APP加载session对象"""
        # session保存数据到redis时启用的链接对象
        app.config["SESSION_REDIS"] = redis_session
        # session存储对象加载配置
        session_store.init_app(app)
    
        # 为日志对象加载配置
        log = logger.init_app(app)
        app.log = log
    
        # 终端脚本工具加载配置
        manager.app = app
    
        return manager
    

    蓝图初始化

    在application下创建apps目录,apps以后专门用于保存项目的每一个蓝图,并在apps创建home蓝图目录

    自定义终端命令生成蓝图目录结构

    1. 通过自定义终端命令, 创建一个自动生成蓝图目录的命令.application/utils/commands.py
    import os, inspect
    
    from flask_script import Command, Option
    from importlib import import_module
    
    # 自定义注册命令
    def load_commands(manager, command_path=None):
        """根据指定导包路径注册自定义命令到manage中"""
        if command_path is None:
            command_path = 'application.utils.commands'
    
        # 根据路径导包
        module = import_module(command_path)
    
        # 提前文件中所有命令类成员
        class_list = inspect.getmembers(module, inspect.isclass)
    	# print( class_list )
        """
        [
            ('BlueprintCommand', <class 'application.utils.commands.BlueprintCommand'>), 
            ('Command', <class 'flask_script.commands.Command'>), 
            ('Option', <class 'flask_script.commands.Option'>)
        ]
        """
        for item in class_list:
            # 判断命令类是否是Command的子类,以为Command也是Command的子类,所有去除Command命令类注册
            if issubclass(item[1],Command) and item[0] != 'Command':
                # 注册命令类到manage中
                manager.add_command(item[1].name, item[1])
    
    # 生成蓝图目录结构
    class BlueprintCommand(Command):
        # 生成蓝图命令名称
        name = 'blue'
    
        # 传递参数
        option_list = [
            Option('-n', '--name', dest='name'),
        ]
    
        # 运行程序
        def run(self, name):
            # 生成蓝图目录结构
            os.mkdir(name)
            open(f'{name}/__init__.py', 'w')
            open(f'{name}/views.py', 'w')
            open(f'{name}/models.py', 'w')
            open(f'{name}/urls.py', 'w')
            open(f'{name}/test.py', 'w')
            open(f'{name}/api.py', 'w')
            open(f'{name}/socket.py', 'w')
            open(f'{name}/tasks.py', 'w')
    
            print(f'蓝图{name}创建完成...')
    
    1. 项目引入文 调用load_command函数注册命令, application/__init__.py
    import os
    
    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 init_config
    from application.utils.logger import Log
    from application.utils.commands import load_commands
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    # - 3.验证相关数据库对象,配置前缀为SESSION
    redis_session = FlaskRedis(config_prefix='SESSION')
    
    # session储存配置初始化
    session_store = Session()
    
    # 自定义日志初始化
    logger = Log()
    
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 当前项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
        redis_session.init_app(app)
    
        """一定先加载默认配置,再传入APP加载session对象"""
        # session保存数据到redis时启用的链接对象
        app.config["SESSION_REDIS"] = redis_session
        # session存储对象加载配置
        session_store.init_app(app)
    
        # 为日志对象加载配置
        log = logger.init_app(app)
        app.log = log
    
        # 终端脚本工具加载配置
        manager.app = app
    
        # 自动注册自定义命令
        load_commands(manager)
    
        return manager
    
    1. 使用终端命令创建蓝图目录结构
    cd application/apps
    python ../../manage.py blue -nhome
    

    注册蓝图

    1. 在开发环境中,建立一个待注册的蓝图应用路径列表, application/settings/dev.py
    """待注册的蓝图应用路径列表"""
    INSTALL_BLUEPRINT = [
        'application.apps.home',
    ]
    
    1. application.utils.blueprint.py模块中声明一个resgister_blueprint函数,函数中针对注册到项目配置文件中的INSTALL_BLUEPRINT蓝图列表选项的蓝图内容实现自动注册到app应用对象里面。
    from flask import Blueprint
    
    # 自动注册蓝图
    def register_blueprint(app):
        # 从配置文件中读取需要注册到项目中的蓝图路径信息
        blueprint_path_list = app.config.get('INSTALL_BLUEPRINT')
    
        # 遍历蓝图路径列表,对每一个蓝图进行初始化
        for blueprint_path in blueprint_path_list:
            # 获取蓝图路径中最后一段的包名作为蓝图的名称
            blueprint_name = blueprint_path.split('.')[-1]
    
            # 创建蓝图对象
            blueprint = Blueprint(blueprint_name, blueprint_path)
    
            # 把蓝图对象注册到app实例对象
            # todo url_prefix 是地址前缀,将来我们将来实现一个总路由来声明它
            app.register_blueprint(blueprint, url_prefix="")
    
    1. 项目引入文件中,调用resgister_blueprint函数,实现自动注册蓝图

    application/__init__.py

    import os
    
    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 init_config
    from application.utils.logger import Log
    from application.utils.commands import load_commands
    from application.utils.bluerprint import register_blueprint
    
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    # - 3.验证相关数据库对象,配置前缀为SESSION
    redis_session = FlaskRedis(config_prefix='SESSION')
    
    # session储存配置初始化
    session_store = Session()
    
    # 自定义日志初始化
    logger = Log()
    
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 当前项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
        redis_session.init_app(app)
    
        """一定先加载默认配置,再传入APP加载session对象"""
        # session保存数据到redis时启用的链接对象
        app.config["SESSION_REDIS"] = redis_session
        # session存储对象加载配置
        session_store.init_app(app)
    
        # 为日志对象加载配置
        log = logger.init_app(app)
        app.log = log
    
        # 自动注册蓝图
        register_blueprint(app)
    
        # 终端脚本工具加载配置
        manager.app = app
    
        # 自动注册自定义命令
        load_commands(manager)
    
        return manager
    

    注册蓝图的路由和视图

    1. application/utils/blueprint.py中生成path函数,把url地址和视图方法映射关系处理成字典
    from flask import Blueprint
    
    # 自动注册蓝图
    def register_blueprint(app):
        # 从配置文件中读取需要注册到项目中的蓝图路径信息
        blueprint_path_list = app.config.get('INSTALL_BLUEPRINT')
    
        # 遍历蓝图路径列表,对每一个蓝图进行初始化
        for blueprint_path in blueprint_path_list:
            # 获取蓝图路径中最后一段的包名作为蓝图的名称
            blueprint_name = blueprint_path.split('.')[-1]
    
            # 创建蓝图对象
            blueprint = Blueprint(blueprint_name, blueprint_path)
    
            # 把蓝图对象注册到app实例对象
            # todo url_prefix 是地址前缀,将来我们将来实现一个总路由来声明它
            app.register_blueprint(blueprint, url_prefix="")
            
    # 把url地址和视图方法映射关系处理成字典   
    def path(rule, view_func, **kwargs):
        """绑定url地址和视图的映射关系"""
        data = {
            'rule':rule,
            'view_func':view_func,
            **kwargs
        }
        return data   
    

    application.__init__入口文件中,导入path路由映射函数,将来方便再其他地方调用该函数

    from application.utils.bluerprint import register_blueprint, path
    
    1. 在home蓝图下的urls.py中,使用path函数绑定视图和路由的映射关系并添加urlpatterns中,home.urls.py
    from application import path
    # 引入当前蓝图应用视图
    from . import views
    
    urlpatterns = [
        path('/index', views.index, methods=['post']),
        path('/demo', views.demo)
    ]
    

    为了方便测试,先到当前home蓝图下视图文件views.py中,添加2个测试的视图

    def index():
        return 'home/views hello!!'
    
    def demo():
        return 'home.views.demo ok'
    
    1. 蓝图注册函数register_blueprint中, 生成蓝图对象以后自动加载并注册蓝图的路由和视图

    application/utils/blueprint.py

    from flask import Blueprint
    # 引入导包函数
    from importlib import import_module
    
    # 自动注册蓝图
    def register_blueprint(app):
        # 从配置文件中读取需要注册到项目中的蓝图路径信息
        blueprint_path_list = app.config.get('INSTALL_BLUEPRINT')
    
        # 遍历蓝图路径列表,对每一个蓝图进行初始化
        for blueprint_path in blueprint_path_list:
            # 获取蓝图路径中最后一段的包名作为蓝图的名称
            blueprint_name = blueprint_path.split('.')[-1]
            # 创建蓝图对象
            blueprint = Blueprint(blueprint_name, blueprint_path)
    
            # 导入子路由关系,blueprint_url_path就是当前蓝图下的urls模块的导包路径
            blueprint_url_path = blueprint_path + '.urls'
            # 导包
            urls_module = import_module(blueprint_url_path)
            # 获取urls模块下路由列表urlpatterns
            urlpatterns = urls_module.urlpatterns
            # 把urlpatterns的每一个路由信息添加注册到蓝图对象里面
            for url in urlpatterns:
                blueprint.add_url_rule(**url)
    
    
            # 把蓝图对象注册到app实例对象
            # todo url_prefix 是地址前缀,将来我们将来实现一个总路由来声明它
            app.register_blueprint(blueprint, url_prefix="")
    
    # 把url地址和视图方法映射关系处理成字典
    def path(rule, view_func, **kwargs):
        """绑定url地址和视图的映射关系"""
        data = {
            'rule':rule,
            'view_func':view_func,
            **kwargs
        }
        return data
    

    此时,运行项目,就可以通过url地址访问蓝图下的视图方法了,postman中

    # get方法:
    http://0.0.0.0:5000/demo
    # post方法
    http://0.0.0.0:5000/index
    
    1. 上面蓝图注册到app示例对象时, 没有设置url_prefix路由前缀, 接下来我们可以单独设置一个总路由application/urls.py,进行路由前缀的设置.

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

    """总路由"""
    URL_PATH = "application.urls"
    

    (2) 创建include函数,负责把路由前缀和蓝图进行绑定映射,application.utils.blueprint

    # 路由前缀和蓝图进行绑定映射
    def include(url_prefix, blueprint_url_subfix):
        """
    
        :param url_prefix: 路由前缀
        :param blueprint_url_subfix: 蓝图路由,
                格式:蓝图包名.路由模块名
                例如:蓝图目录是home, 路由模块名是urls,则参数:home.urls
        :return:
        """
        data = {
            "url_prefix": url_prefix,
            "blueprint_url_subfix": blueprint_url_subfix
        }
        return data
    

    application.__init__入口文件中,导入include函数,将来方便再其他地方调用该函数

    from application.utils.bluerprint import register_blueprint, path, include
    

    (3) 总路由文件注册蓝图和路由前缀的关系到列表中, application/urls.py,

    from application import include
    
    # 蓝图子路由列表
    urlpatterns = [
        include('/home','home.urls')
    ]
    

    (4) 接下来,就可以在注册蓝图时,把路由前缀随着蓝图对象一起注册到app实例对象中

    application/utils/blueprint.py

    from flask import Blueprint
    # 引入导包函数
    from importlib import import_module
    
    # 自动注册蓝图
    def register_blueprint(app):
        # 从配置文件中读取总路由路径信息
        app_urls_path = app.config.get('URL_PATH')
        # 导包,导入总路由模块
        app_urls_module = import_module(app_urls_path)
        # 获取总路由列表
        app_urlpatterns = app_urls_module.urlpatterns
    
        # 从配置文件中读取需要注册到项目中的蓝图路径信息
        blueprint_path_list = app.config.get('INSTALL_BLUEPRINT')
        # 遍历蓝图路径列表,对每一个蓝图进行初始化
        for blueprint_path in blueprint_path_list:
            # 获取蓝图路径中最后一段的包名作为蓝图的名称
            blueprint_name = blueprint_path.split('.')[-1]
            # 创建蓝图对象
            blueprint = Blueprint(blueprint_name, blueprint_path)
    
            # 蓝图路由的前缀
            url_prefix = ""
            # 蓝图下的子路由列表
            urlpatterns = []
    
            # 获取蓝图的父级目录, 即application/apps
            blueprint_father_path =  ".".join( blueprint_path.split(".")[:-1] )
            # 循环总路由列表
            for item in app_urlpatterns:
                # 判断当前蓝图是否在总路由列表中
                if blueprint_name in item["blueprint_url_subfix"]:
                    # 导入蓝图下的子路由模块
                    urls_module = import_module(blueprint_father_path + "." + item["blueprint_url_subfix"])
                    # 获取urls模块下路由列表urlpatterns
                    urlpatterns = urls_module.urlpatterns
                    # 提取蓝图路由的前缀
                    url_prefix = item["url_prefix"]
                    # 从总路由中查到当前蓝图对象的前缀就不要继续往下遍历了
                    break
    
            for url in urlpatterns:
                blueprint.add_url_rule(**url)
    
            # 把蓝图对象注册到app实例对象,并添加路由前缀
            app.register_blueprint(blueprint, url_prefix=url_prefix)
    
    # 把url地址和视图方法映射关系处理成字典
    def path(rule, view_func, **kwargs):
        """绑定url地址和视图的映射关系"""
        data = {
            'rule':rule,
            'view_func':view_func,
            **kwargs
        }
        return data
    
    # 路由前缀和蓝图进行绑定映射
    def include(url_prefix, blueprint_url_subfix):
        """
    
        :param url_prefix: 路由前缀
        :param blueprint_url_subfix: 蓝图路由,
                格式:蓝图包名.路由模块名
                例如:蓝图目录是home, 路由模块名是urls,则参数:home.urls
        :return:
        """
        data = {
            "url_prefix": url_prefix,
            "blueprint_url_subfix": blueprint_url_subfix
        }
        return data
    
    

    注册蓝图的模型

    1. 在蓝图home下的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
    
    1. 在自动注册蓝图对象时,导入模型,让flask识别到。

    application/utils/blueprint.py

    from flask import Blueprint
    # 引入导包函数
    from importlib import import_module
    
    # 自动注册蓝图
    def register_blueprint(app):
        # 从配置文件中读取总路由路径信息
        app_urls_path = app.config.get('URL_PATH')
        # 导包,导入总路由模块
        app_urls_module = import_module(app_urls_path)
        # 获取总路由列表
        app_urlpatterns = app_urls_module.urlpatterns
    
        # 从配置文件中读取需要注册到项目中的蓝图路径信息
        blueprint_path_list = app.config.get('INSTALL_BLUEPRINT')
        # 遍历蓝图路径列表,对每一个蓝图进行初始化
        for blueprint_path in blueprint_path_list:
            # 获取蓝图路径中最后一段的包名作为蓝图的名称
            blueprint_name = blueprint_path.split('.')[-1]
            # 创建蓝图对象
            blueprint = Blueprint(blueprint_name, blueprint_path)
    
            # 蓝图路由的前缀
            url_prefix = ""
            # 蓝图下的子路由列表
            urlpatterns = []
    
            # 获取蓝图的父级目录, 即application/apps
            blueprint_father_path =  ".".join( blueprint_path.split(".")[:-1] )
            # 循环总路由列表,获取当前蓝图的路由列表和路由前缀
            for item in app_urlpatterns:
                # 判断当前蓝图是否在总路由列表中
                if blueprint_name in item["blueprint_url_subfix"]:
                    # 导入蓝图下的子路由模块
                    urls_module = import_module(blueprint_father_path + "." + item["blueprint_url_subfix"])
                    # 获取urls模块下路由列表urlpatterns
                    urlpatterns = urls_module.urlpatterns
                    # 提取蓝图路由的前缀
                    url_prefix = item["url_prefix"]
                    # 从总路由中查到当前蓝图对象的前缀就不要继续往下遍历了
                    break
    
            # 注册蓝图路由
            for url in urlpatterns:
                blueprint.add_url_rule(**url)
    
            # 导入蓝图模型
            import_module(blueprint_path + '.models')
    
            # 把蓝图对象注册到app实例对象,并添加路由前缀
            app.register_blueprint(blueprint, url_prefix=url_prefix)
    
    # 把url地址和视图方法映射关系处理成字典
    def path(rule, view_func, **kwargs):
        """绑定url地址和视图的映射关系"""
        data = {
            'rule':rule,
            'view_func':view_func,
            **kwargs
        }
        return data
    
    # 路由前缀和蓝图进行绑定映射
    def include(url_prefix, blueprint_url_subfix):
        """
    
        :param url_prefix: 路由前缀
        :param blueprint_url_subfix: 蓝图路由,
                格式:蓝图包名.路由模块名
                例如:蓝图目录是home, 路由模块名是urls,则参数:home.urls
        :return:
        """
        data = {
            "url_prefix": url_prefix,
            "blueprint_url_subfix": blueprint_url_subfix
        }
        return data
    
    1. 在项目入口文件中通过 db的 create_all() 创建数据表。application/__init__.py
    import os
    
    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 init_config
    from application.utils.logger import Log
    from application.utils.commands import load_commands
    from application.utils.bluerprint import register_blueprint, path, include
    
    
    # 终端脚本工具初始化
    manager = Manager()
    
    # SQLAlchemy初始化
    db = SQLAlchemy()
    
    # redis数据库初始化
    # - 1.默认缓存数据库对象,配置前缀为REDIS
    redis_cache = FlaskRedis(config_prefix='REDIS')
    # - 2.验证相关数据库对象,配置前缀为CHECK
    redis_check = FlaskRedis(config_prefix='CHECK')
    # - 3.验证相关数据库对象,配置前缀为SESSION
    redis_session = FlaskRedis(config_prefix='SESSION')
    
    # session储存配置初始化
    session_store = Session()
    
    # 自定义日志初始化
    logger = Log()
    
    
    # 全局初始化
    def init_app(config_path):
        """全局初始化 - 需要传入加载开发或生产环境配置路径"""
        # 创建app应用对象
        app = Flask(__name__)
    
        # 当前项目根目录
        app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
        # 开发或生产环境加载配置
        init_config(app, config_path)
    
        # SQLAlchemy加载配置
        db.init_app(app)
    
        # redis加载配置
        redis_cache.init_app(app)
        redis_check.init_app(app)
        redis_session.init_app(app)
    
        """一定先加载默认配置,再传入APP加载session对象"""
        # session保存数据到redis时启用的链接对象
        app.config["SESSION_REDIS"] = redis_session
        # session存储对象加载配置
        session_store.init_app(app)
    
        # 为日志对象加载配置
        log = logger.init_app(app)
        app.log = log
    
        # 自动注册蓝图
        register_blueprint(app)
    
        # 注册模型,创建表
        with app.app_context():
            db.create_all()
    
        # 终端脚本工具加载配置
        manager.app = app
    
        # 自动注册自定义命令
        load_commands(manager)
    
        return manager
    

    此时创建项目目录结构 - 2

    mofang						# 项目根目录
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ __init__.py       # 项目默认初始化配置文件
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   └ prod.py           # 生产阶段的配置文件
    │   ├── __init__.py         # 项目初始化全局引导文件
    |   ├── utils/              # 项目工具类库目录
    │   │   ├ blueprint.py      # 蓝图注册相关的函数
    │   │   ├ commands.py       # 自定义命令和加载命令的相关函数
    │   │   ├ config.py         # 项目配置加载的辅助函数
    │   │   └ logger.py         # 日志模块
    │   ├── apps/               # 保存项目中所有蓝图的存储目录
    │   │   ├── home            # 蓝图目录【这里是举例而已】
    │   │   │   ├── __init__.py # 蓝图的初始化文件
    │   │   │   ├── urls.py     # 蓝图的子路由文件
    │   │   │   ├── models.py   # 蓝图的模型文件
    │   │   │   └── views.py    # 蓝图的视图文件
    │   │   ├── __init__.py
    │   └── urls.py              # 总路由
    ├── manage.py               # 项目的终端管理脚本文件
    
  • 相关阅读:
    如何自定义一个通信协议
    c++ 如何编写接口类(interface)
    QT国际化(中英转换)
    QT中文乱码与国际化支持
    frp官方中文文档
    K3 LEDE固件更改FRP客户端版本
    Linux下的tar压缩解压缩命令详解
    QT入门系列(3):控制台输出QString
    Delphi、Lazarus保留字、关键字详解
    使用TortoiseSVN的客户端钩子脚本触发Jenkins构建
  • 原文地址:https://www.cnblogs.com/jia-shu/p/14830653.html
Copyright © 2011-2022 走看看