通过工厂函数封装返回app对象
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:root@127.0.0.1:3306/toutiao"
SQLALCHEMY_BINDS = {
# 一般主库和从库对外访问也是使用高可用的方案,所以一般会访问VIP虚拟IP,所以一般一个就够了
"master": "mysql://root:root@127.0.0.1:3306/toutiao",
"slave": "mysql://root:root@127.0.0.1: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,
}
通过工厂函数封装返回app对象的更多相关文章
- js valueOf()函数用于返回指定对象的原始值
valueOf()函数用于返回指定对象的原始值. 该方法属于Object对象,由于所有的对象都"继承"了Object的对象实例,因此几乎所有的实例对象都可以使用该方法. 对象 返回 ...
- SpringMVC 封装返回结果对象
/*** *请求返回的最外层对象 **/ public class Result<T>{ /*错误码*/ private Integer code; /*提示信息*/ private St ...
- Javascript我学之六对象工厂函数与构造函数
本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript ...
- js对象工厂函数与构造函数
转自:http://www.cnblogs.com/Jener/p/5920963.html ★概述: 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法.然而 ...
- jQuery分析(2) - $工厂函数分析
前言 从这节进入jQuery的世界,首先从jQuery的入口函数开始了解jQuery()或$是如何运作的,这里我给出了一个最小的例子来分析. 回忆 在进入分析代码前我们回想下jQuery的使用方法有哪 ...
- JavaScript中的工厂函数
所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个类实例. 在学习jQuery的时候,我们经常会看到“工厂函数”这个概念,那么究竟什么是“工厂函数”呢?我们来看看概念,“所 ...
- Python 工厂函数和内建函数
工厂函数 工厂函数都是类对象, 即当你调用他们时, 创建的其实是一个类实例 例如: str(), list(), tuple()... 内建函数 内建函数通常是python自定义的一些函数, 这些函数 ...
- props default 数组/对象的默认值应当由一个工厂函数返回
export default {props: { slides:{ type:Array, default:[] } },这是我的代码 报错是Invalid default value for pro ...
- Invalid default value for prop "value": Props with type Object/Array must use a factory function to return the default value.(props default 数组/对象的默认值应当由一个工厂函数返回)
Invalid default value for prop "value": Props with type Object/Array must use a factory fu ...
- 关于props default 数组/对象的默认值应当由一个工厂函数返回
export default {props: { xAxisData: { type: Array, default: [] }, },这是我的代码 报错是Invalid default va ...
随机推荐
- WPF学习 - 动画基础(1)
1. WPF中的动画(Animation),是一种属性动画.技术上来说,它是让属性从一个值,变化到另一个值的过程.因此,有两条重要的特性: 1.1 只能为依赖属性应用动画(因为第二条特性). 1.2 ...
- TypeScript中Class基础使用
TypeScript是一种静态类型的JavaScript超集,它提供了许多增强的功能,其中之一就是对面向对象编程的支持.在TypeScript中,我们可以使用Class来定义类,这使得我们能够更加结构 ...
- 【译】在 Visual Studio 2022 中安全地在 HTTP 请求中使用机密
在 Visual Studio 2022 的17.8 Preview 1版本中,我们更新了 HTTP 文件编辑器,使您能够外部化变量,从而使跨不同环境的 Web API 测试更容易.此更新还包括以安全 ...
- 数据库重构之路,以 OrientDB 到 NebulaGraph 为例
"本文由社区用户 @阿七从第一视角讲述其团队重构图数据库的过程,首发于阿七公众号「浅谈架构」" 原文出处:https://mp.weixin.qq.com/s/WIJNq-nuuA ...
- GO 中的时间操作(time & dateparse)【GO 基础】
〇.前言 日常开发过程中,对于时间的操作可谓是无处不在,但是想实现时间自由还是不简单的,多种时间格式容易混淆,那么本文将进行梳理,一起学习下. 官方提供的库是 time,功能很全面,本文也会详细介绍. ...
- warning in ./src/router/index.js (Emitted value instead of an instance of Error) Error compiling template: Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'jsoninfo'
目录 warning in ./src/router/index.js (Emitted value instead of an instance of Error) Error compiling ...
- MASA MAUI iOS 文件下载与断点续传
@ 目录 背景 介绍 方案及代码 1.新建MAUI项目 2.建立NSUrlSession会话连接 3.使用NSUrlSessionDownloadTask 创建下载任务 4.DidWriteData ...
- 其它——ZeroRPC和SimpleXMLRPCServer
文章目录 一 Python中RPC框架 二 SimpleXMLRPCServer使用 服务端 客户端 三 ZeroRPC使用 服务端 客户端 一 Python中RPC框架 自带的:SimpleXMLR ...
- jmeter的全局变量(将登陆token设置全局)
1.首先调用登陆接口,用json提取器,取出响应内的token值 2.在beanshell取样器中设置全局变量 //设置全局变量方法一:用函数__setProperty设置${__setProper ...
- 02-RAID技术 学习心得
RAID 术语 扇区:是磁盘中最小的存储单元,向磁盘读写数据时是以扇区为最小单元进行存储 block:block,是由N个扇区组成一个块: 在磁盘相同偏移处横向逻辑分割,就形成了stripee: 一个 ...