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对象的更多相关文章

  1. js valueOf()函数用于返回指定对象的原始值

    valueOf()函数用于返回指定对象的原始值. 该方法属于Object对象,由于所有的对象都"继承"了Object的对象实例,因此几乎所有的实例对象都可以使用该方法. 对象 返回 ...

  2. SpringMVC 封装返回结果对象

    /*** *请求返回的最外层对象 **/ public class Result<T>{ /*错误码*/ private Integer code; /*提示信息*/ private St ...

  3. Javascript我学之六对象工厂函数与构造函数

    本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript ...

  4. js对象工厂函数与构造函数

    转自:http://www.cnblogs.com/Jener/p/5920963.html ★概述:         使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法.然而 ...

  5. jQuery分析(2) - $工厂函数分析

    前言 从这节进入jQuery的世界,首先从jQuery的入口函数开始了解jQuery()或$是如何运作的,这里我给出了一个最小的例子来分析. 回忆 在进入分析代码前我们回想下jQuery的使用方法有哪 ...

  6. JavaScript中的工厂函数

    所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个类实例. 在学习jQuery的时候,我们经常会看到“工厂函数”这个概念,那么究竟什么是“工厂函数”呢?我们来看看概念,“所 ...

  7. Python 工厂函数和内建函数

    工厂函数 工厂函数都是类对象, 即当你调用他们时, 创建的其实是一个类实例 例如: str(), list(), tuple()... 内建函数 内建函数通常是python自定义的一些函数, 这些函数 ...

  8. props default 数组/对象的默认值应当由一个工厂函数返回

    export default {props: { slides:{ type:Array, default:[] } },这是我的代码 报错是Invalid default value for pro ...

  9. 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 ...

  10. 关于props default 数组/对象的默认值应当由一个工厂函数返回

    export default {props: { xAxisData: {   type: Array,   default: [] }, },这是我的代码 报错是Invalid default va ...

随机推荐

  1. Linux Ubuntu 安装Qt【安装完可以直接运行】

    1.安装 Qt: 第一步:到官网http://download.qt.io/archive/qt/下载 Qt 安装包,此处本人安装的是 qt-opensource-linux-x64-5.7.0.ru ...

  2. 文心一言 VS 讯飞星火 VS chatgpt (99)-- 算法导论9.3 5题

    五.用go语言,假设你已经有了一个最坏情况下是线性时间的用于求解中位数的"黑箱"子程序.设计一个能在线性时间内解决任意顺序统计量的选择问题算法. 文心一言: 为了在线性时间内解决任 ...

  3. NineData SQL 窗口支持深色模式,让程序员不再怕长期用眼!

    您有没有尝试过被明亮的显示器闪瞎眼的经历? 在夜间或低光环境下,明亮的界面会导致许多用眼健康问题,例如长时间使用导致的眼睛疲劳.干涩和不适感,同时夜间还可能会抑制褪黑素分泌,给您的睡眠质量带来影响. ...

  4. python系列:argparse详解 外部传参给python的库

    一.argparse简介 argparse 模块是 Python 内置的用于命令项选项与参数解析的模块,argparse 模块可以让人轻松编写用户友好的命令行接口,能够帮助程序员为模型定义参数. ar ...

  5. CF1526C1

    题目简化和分析: 给您一个数组,在其中选择若干个数使得: 任意前缀和 \(\ge 0\) 数量尽可能的大 我们可以使用贪心策略,策略如下: 如果当前数为非负,必喝. 而毒药尽可能的多喝,如果喝没了,就 ...

  6. 小提琴图的绘制方法:Python matplotlib实现

      本文介绍基于Python中matplotlib模块与seaborn模块,利用多个列表中的数据,绘制小提琴图(Violin Plot)的方法.   小提琴图作为一种将箱型图与核密度图分别所能表达的信 ...

  7. ABP中关于Swagger的一些配置

    Abp 集成 Swagger 官方文档, 请参考 Swagger Integration AspNetCore 配置 Swagger, 请参考 Swashbuckle.AspNetCore 本文的项目 ...

  8. 自然数的拆分问题(lgP2404)

    dfs.又调了一个小时,窝果然菜 需要传递的变量分别为目前搜索的数字:目前所有选中数字的和:目前所选数字个数. 见注释. #include<bits/stdc++.h> using nam ...

  9. PTA乙级1039(C++)散列表解法

    题目 1039 到底买不买  小红想买些珠子做一串自己喜欢的珠串.卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖. 于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要的珠子?如 ...

  10. react,es6的括号问题

    JavaScript 会自动给行末添加分号.如果 return 后面换行不加括号就会变成 return;. 就是说因为jsx语句跨行了,如果写在一行是可以省略小括号的. const About = ( ...