首页 > 其他分享 >通过工厂函数封装返回app对象

通过工厂函数封装返回app对象

时间:2023-10-04 12:35:47浏览次数:39  
标签:blueprint 封装 函数 flask True app import config

main.py #主文件

import os

from app import create_app

# 通过环境变量设置项目运行时使用的配置文件,这里就手动设置以下了,一般部署的时候通过脚本等设置。
# os.environ.setdefault("APP_ENV", "dev")

app = create_app(os.environ.get("APP_ENV", "dev"))


@app.route('/')
def all_route():
    """返回所有路由信息"""
    rules = app.url_map.iter_rules()
    print(os.environ.get("APP_ENV"))
    return [i.__repr__() for i in rules]

app/init.py

import os.path
import sys

import grpc
from flask import Flask
from flask_apscheduler.auth import HTTPBasicAuth
from flask_cors import CORS
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from redis.client import Redis
from redis.cluster import RedisCluster, ClusterNode
from sqlalchemy.exc import OperationalError

from app.settings import constants
from app.settings.configs import config_dict


try:
    import pymysql
    pymysql.install_as_MySQLdb()
except:
    pass

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 将common加入到模块搜索路径
sys.path.append(os.path.join(BASE_DIR, "common"))

from utils.db_read_write_separation import MYSession
# db对象
# 调用session_options传递自己的Session类,实现读写分离
# db = SQLAlchemy(session_options={"class_": MYSession, 'twophase': True})
# 开启二阶段提交,但是全部session都会启动xa,性能有所影响
db = SQLAlchemy(session_options={"class_": MYSession})

## REDIS
# 暴露redis引用
# 因为flask-app是延迟加载,而我们需要将redis的配置信息从flask-app的config中读取,所以先给None,
# redis_cli: Redis = None
redis_cluster: RedisCluster = None

## Flask-APScheduler
# Flask-APScheduler 别人基于APScheduler封装,方便Flask中使用
from flask_apscheduler import APScheduler
# 先初始化,然后在create app工厂函数里面再执行init_app() ,这点和Flask-SQLAlchemy一样...
scheduler = APScheduler()

## RPC调用相关
#### rpc  ####
recommend_rpc: grpc.Channel = None

# 创建flask app对象函数
def create_flask_app(env):
    """
    创建app对象并返回
    :param env: 加载指定环境的配置文件
    :return: app实例
    """
    app = Flask(__name__)
    # 根据传递进来的env获取对象类型的配置文件并加载
    app.config.from_object(config_dict[env])

    # 然后再从环境变量加载覆盖配置(可以用于覆盖配置、或则迷惑别人...比如SECRET_KEY,你并不想别人知道,你就可以用这种方式。)
    # 从环境变量指向的配置文件中读取的配置信息会覆盖掉从配置对象中加载的同名参数
    # slient : 如果是True则表示即便没有这个环境遍历,也不会抛出异常。默认为False
    app.config.from_envvar(constants.EXTRA_CONFIG_FROM_ENV_NAME,
                           silent=True)  # SECRET_CONFIG变量设置为一个配置文件的相对或者绝对路径,文件里面的配置项是k=v

    # # 返回json设置相关:
    # # 需要注意的是json默认是会对中文进行ascii编码,需要再flask的配置中设置
    # # flask 2.2之前:
    # # app.config["JSON_AS_ASCII"] = False
    # # flask 2.2之后。原因:2.2提供了一个JsonProvider : https://github.com/pallets/flask/pull/4692
    # # 拓展:使用orjson,这个json库比较好的样子?有空看看。https://www.jb51.net/article/250451.htm
    # app.json.ensure_ascii = False
    # 这里我再定义一个自定义配置项来设置
    app.json_provider_class.ensure_ascii = app.config.get("ADV_FLASK_ENSURE_ASCII", True)

    return app


def create_app(env):
    # 拿到flask的app对象
    app = create_flask_app(env)

    # 注册扩展组件
    register_extra(app)

    # 注册url参数转换器
    from utils.converters import register_converters
    register_converters(app)

    # 统一注册蓝图
    register_blueprint(app)

    # 统一异常处理
    from utils import exceptions
    app.errorhandler(exceptions.DBException)(exceptions.database_error)
    app.errorhandler(OperationalError)(exceptions.operational_error)

    return app


def register_extra(app):
    """
    将一些额外的初始化统一放到该方法中
    :param app:
    :return:
    """

    # 初始化数据库
    db.init_app(app)

    # 初始化redis
    # global redis_cli
    # redis_cli = Redis(
    #     host=app.config["REDIS_HOST"],
    #     port=app.config["REDIS_PORT"],
    #     db=app.config["REDIS_SELECT_DB"],
    #     decode_responses=True
    # )

    nodes_config = app.config["REDIS_CLUSTER_NODES"]
    # 现在新版要求传的是ClusterNode对象了,所以读取出配置的host和port,然后创建对象传参进去
    nodes = []
    for node in nodes_config:
        nodes.append(ClusterNode(node["host"], node["port"]))

    global redis_cluster
    redis_cluster = RedisCluster(startup_nodes=nodes, decode_responses=True, socket_connect_timeout=5)

    # 数据迁移
    Migrate(app, db)
    # 导入模型类【一定要记得!】
    from app.modules.users.models import User, Relation
    from app.modules.channels.models import UserChannel, Channel
    from app.modules.articles.models import Article, ArticleContent, Comment


    # 请求钩子注入
    # 每次请求进来之前,判断是否有token,并校验token
    # 将token中的用户id、是否刷新token标志位写入到g对象中,方便后续视图类、视图函数判断是否有登录。
    from utils.middlewares import get_userid
    app.before_request(get_userid)


    ### 跨域, flask-cors ###
    cors = CORS(app)

    # Flask-APScheduler
    scheduler.init_app(app)
    # https://github.com/viniciuschiele/flask-apscheduler/blob/master/examples/auth.py
    # scheduler.auth = HTTPBasicAuth()  # 进入flask-apscheduler提供的api管理视图认证方式类
    # scheduler.authenticate(lambda x: True)  # 授权方法,只要方法中返回true就是认证通过
    # 导入任务
    from .tasks import tasks
    # 为了防止任务中可能会需要用到FLASK上下文,所以还是用app.app_context()
    with app.app_context():
        scheduler.start()

    ### gRPC ###
    global recommend_rpc
    recommend_rpc = grpc.insecure_channel(app.config["RPC_SERVERS"]["recommend"])

    # 其他的rpc.....以此类推...
    # global video_rpc
    # video_rpc = grpc.insecure_channel(app.config["RPC_SERVERS"]["video"])



def register_blueprint(app):
    """将注册蓝图的操作统一方法这个函数中"""
    from app.modules.users import user_blueprint
    from app.modules.verify import verify_blueprint
    from app.modules.channels import channels_blueprint
    from app.modules.articles import article_blueprint
    # url_prefix可以在app注册蓝图的时候写,也可以在蓝图对象实例中指定,如:user_blueprint = Blueprint("users", __name__,url_prefix="/user")
    # 如果同时指定,以app.register_blueprint方法中指定的为准
    app.register_blueprint(user_blueprint, url_prefix="/user")
    app.register_blueprint(verify_blueprint, url_prefix="/verify")
    app.register_blueprint(channels_blueprint, url_prefix="/channels")
    app.register_blueprint(article_blueprint, url_prefix="/articles")

settings/configs.py

class DefaultConfig:
    # 使用flask中的session要配置SECRET_KEY
    SECRET_KEY = "sdDSFGy981^&*(-31wzz-c0546511"

    # 这个变量是自定义的,用来确保Flask默认的response返回jsop字符串确保不经过ascii编码
    ADV_FLASK_ENSURE_ASCII = False

    # restful-json返回中文不经过ascii编码
    RESTFUL_JSON = {
        "ensure_ascii": False
    }

    ### SQLALCHEMY配置相关 ###
    # app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
    SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]:3306/toutiao"

    SQLALCHEMY_BINDS = {
        # 一般主库和从库对外访问也是使用高可用的方案,所以一般会访问VIP虚拟IP,所以一般一个就够了
        "master": "mysql://root:[email protected]:3306/toutiao",
        "slave": "mysql://root:[email protected]:3306/toutiao",
    }
    # 显示ORM执行的SQL语句
    SQLALCHEMY_ECHO = False

    # 如果启用,将记录请求期间每个查询的信息。使用get_recorded_queries()获取请求期间发出的查询列表。
    # 用于分析慢查询
    SQLALCHEMY_RECORD_QUERIES = False

    # 跟踪,关闭它,不然有性能影响
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    ### JWT配置相关 ###
    # JWT SECRET KEY
    JWT_SECRET_KEY = 'xiuagTFxgx..ADFEaiuxdbjas$#$1%$$&8-12du91234562'


    ### 七牛云对象存储OSS ###
    QINIU_ACCESS_KEY = "PTXRkpavqT1AZVgyYDMXNqG0021DzZJwQsGEZVMM"
    QINIU_SECRET_KEY = "DhlG5zdhj0Cxkicaf4G_udkMY5wgqUYLHI-3kMFM"
    QINIU_BASEURL = "http://rvdfduarm.hn-bkt.clouddn.com/"
    QINIU_BUCKET_NAME = "juelian-bbs-img"  # 要上传的空间


    ### 跨越设置 ###
    # 让flask-cors直接读取配置文件。
    CORS_ORIGINS = [
        "http://127.0.0.1:8080",
        "https://127.0.0.1:8080",
        "http://127.0.0.1:5000",
        "https://127.0.0.1:5000",
    ]
    CORS_MAX_AGE = 86400
    CORS_SUPPORTS_CREDENTIALS = True


    #### APScheduler ####
    # 这个和flask中的jsonify()函数有关,但是不知道为啥默认应该就是True的,FLASK-APScheduler会找不到,所以手动设置一下。。
    JSONIFY_PRETTYPRINT_REGULAR = True

    # 开启API查询功能,给你提供了很多接口,是Flask-APScheduler额外提供的功能
    SCHEDULER_API_ENABLED = True
    # api接口的前缀,默认是/schedule
    # SCHEDULER_API_PREFIX: str(default: "/scheduler")
    SCHEDULER_API_PREFIX = "/apscheduler"
    # SCHEDULER_ENDPOINT_PREFIX: str(default: "scheduler.")
    # 允许访问的主机
    # SCHEDULER_ALLOWED_HOSTS: list(default: ["*"])



    #### RPC 服务器 ####
    RPC_SERVERS = {
        "recommend": "127.0.0.1:7888",
        "video": "127.0.0.1:8888",
        "news": "127.0.0.1:9888",
    }


class DevConfig(DefaultConfig):
    DEBUG = True

    # 显示ORM执行的SQL语句
    SQLALCHEMY_ECHO = True

    # 如果启用,将记录请求期间每个查询的信息。使用get_recorded_queries()获取请求期间发出的查询列表。
    # 用于分析慢查询
    SQLALCHEMY_RECORD_QUERIES = True

    # REDIS信息
    REDIS_HOST = "10.0.1.140"
    REDIS_PORT = 30817
    REDIS_SELECT_DB = 0

    # 定义redis集群的Node节点信息
    # 注意不一定要全部集群的节点信息都放在这里,因为RedisCluster只要求集群中其中一个节点即可!
    REDIS_CLUSTER_NODES = [
        {"host": "192.168.2.6", "port": 7000},
        {"host": "192.168.2.6", "port": 7001},
        {"host": "192.168.2.6", "port": 7002},
    ]


class ProductConfig(DefaultConfig):
    DEBUG = False

    # REDIS信息
    REDIS_HOST = "10.0.1.140"
    REDIS_PORT = 30817
    REDIS_SELECT_DB = 0
    pass


class TestConfig(DefaultConfig):
    DEBUG = True


config_dict = {
    "dev": DevConfig,
    "prod": ProductConfig,
    "test": TestConfig,
}

标签:blueprint,封装,函数,flask,True,app,import,config
From: https://www.cnblogs.com/juelian/p/17742130.html

相关文章

  • flask自带的异常抛出函数abort
    flask中有一个abort函数,可以用于快捷的抛出异常,但是只能抛出标准的HTTP状态码,不能乱设置HTPP状态码,比如666、777这种。[email protected]("/user")defuser():abort(404)......
  • flask上下文、g变量、current_app
    在flask中的上下文分为两种:请求上下文(requestcontext)也就是和请求相关的上下文,记录一些请求相关的数据。包含:1、request请求对象2、session会话应用上下文(appcontext)记录一些和flask的应用(app=Flask(name))的上下文数据,主要包含:**1、current_app**在项目其它......
  • Qemu源码分析(11)—Apple的学习笔记
    一,前言昨天了解了qemu中虚拟开发板的内存创建,接着再了解下中断创建和使用。二,分析昨天看了flash初始化,后面的我理解应该一样,接着发现sram初始化后,本来以为和flash是一样的,结果多了如下一句,通过注释也很好理解就是把1个bit展开为了1个byte,这样1M的sram变成了32M空间。//Bitbandthe......
  • 库函数之字符函数与字符串函数(上)
    前言......
  • 一 . 格式化输出函数 scanf
    scanf函数的功能是格式化输出任意数据列表,其一般调用格式为:scanf(格式控制符,地址列表)。【说明】(1)地址列表中给出各变量的地址,可以为变量的地址,以&开头,也可以为数组,字符串的首地址。(2)格式控制符由%和格式符组成,作用是将要输入的字符按指定的格式输入如%d,%c......
  • printf函数 和 scangf函数 的格式符
       ......
  • Python入门系列7-函数进阶
    一、函数参数和返回值的作用函数根据有没有参数以及有没有返回值,可以相互组合一共有4种组合方式:1.无参数,无返回值2.无参数,有返回值3.有参数,无返回值4.有参数,有返回值如果函数内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部,如果希望一个函数执行完成后,向外界汇报执行......
  • MySQL聚合函数及分组查询
    本文列举数据库的聚合函数及分组查询的实际使用,以员工表和部门表作为举例:部门表:dept点击查看创建部门表sqlcreate table `dept`  (  `deptno` int(2) not null,  `dname` varchar(14),  `loc` varchar(13),  primary key (`deptno`));员工表:emp点击查......
  • SQL的RAND()函数无参数、带参数用法
    SQL的RAND()函数用于生成一个随机数,其返回值范围是0(包含)到1(不包含)之间的浮点数。RAND()函数在不同的数据库中可能有一些差异,下面是一些常见的用法和示例,用中文回答:1.无参数用法:MySQL:SELECTRAND();返回一个0到1之间的随机浮点数。SQLServer:SELECTRAND();返回一个0到1之间......
  • 分布律,概率分布函数,概率密度函数
    1.分布律定义分布律只针对离散型随机变量,连续型没有设离散型随机变量可能取值为\(x_k(k=1,2,...)\),事件\(\{X=x_k\}\)的概率为离散型随机变量\(X\)的分布律,记作\(P\{X=x_k\}=p_k,k=1,2...\)性质\(p_k>=0\)。\(p_k\)的意思是取值为k的概率\(\sum_{k=1}^{\infty}=1\)......