setting.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. # -*- coding: utf-8 -*-
  2. import os
  3. from functools import lru_cache
  4. from pathlib import Path
  5. from typing import Any, List, Optional, Literal
  6. from pydantic_settings import BaseSettings, SettingsConfigDict
  7. from urllib.parse import quote_plus
  8. from app.common.enums import EnvironmentEnum
  9. from app.config.path_conf import BASE_DIR, ENV_DIR
  10. class Settings(BaseSettings):
  11. """系统配置类"""
  12. model_config = SettingsConfigDict(
  13. env_file=ENV_DIR / f".env.{os.getenv('ENVIRONMENT')}",
  14. env_file_encoding="utf-8",
  15. extra='ignore',
  16. case_sensitive=True, # 区分大小写
  17. )
  18. # ================================================= #
  19. # ******************* 项目环境 ****************** #
  20. # ================================================= #
  21. ENVIRONMENT: EnvironmentEnum = EnvironmentEnum.DEV
  22. # ================================================= #
  23. # ******************* 服务器配置 ****************** #
  24. # ================================================= #
  25. SERVER_HOST: str = '0.0.0.0' # 允许访问的IP地址
  26. SERVER_PORT: int = 8001 # 服务端口
  27. # ================================================= #
  28. # ******************* API文档配置 ****************** #
  29. # ================================================= #
  30. DEBUG: bool = True # 调试模式
  31. TITLE: str = "🎉 FastapiAdmin 🎉 -dev" # 文档标题
  32. VERSION: str = '0.1.0' # 版本号
  33. DESCRIPTION: str = "该项目是一个基于python的web服务框架,基于fastapi和sqlalchemy实现。" # 文档描述
  34. SUMMARY: str = "接口汇总" # 文档概述
  35. DOCS_URL: str = "/docs" # Swagger UI路径
  36. REDOC_URL: str = "/redoc" # ReDoc路径
  37. ROOT_PATH: str = "/api/v1" # API路由前缀
  38. # ================================================= #
  39. # ******************** 跨域配置 ******************** #
  40. # ================================================= #
  41. CORS_ORIGIN_ENABLE: bool = True # 是否启用跨域
  42. # ALLOW_ORIGINS: List[str] = ["*"] # 允许的域名列表
  43. ALLOW_ORIGINS: List[str] = [
  44. 'http://127.0.0.1:8001',
  45. 'http://localhost:5180',
  46. ] # 允许的域名列表
  47. ALLOW_METHODS: List[str] = ["*"] # 允许的HTTP方法
  48. ALLOW_HEADERS: List[str] = ["*"] # 允许的请求头
  49. ALLOW_CREDENTIALS: bool = True # 是否允许携带cookie
  50. CORS_EXPOSE_HEADERS: list[str] = ['X-Request-ID']
  51. # ================================================= #
  52. # ******************* 登录认证配置 ****************** #
  53. # ================================================= #
  54. SECRET_KEY: str = "vgb0tnl9d58+6n-6h-ea&u^1#s0ccp!794=krylxcjq75vzps$" # JWT密钥
  55. ALGORITHM: str = "HS256" # JWT算法
  56. ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 60 * 24 * 1 # access_token过期时间(秒)1 天
  57. REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 60 * 24 * 7 # refresh_token过期时间(秒)7 天
  58. TOKEN_TYPE: str = "bearer" # token类型
  59. TOKEN_REQUEST_PATH_EXCLUDE: list[str] = [ # JWT / RBAC 路由白名单
  60. 'api/v1/auth/login',
  61. ]
  62. # ================================================= #
  63. # ******************** 数据库配置 ******************* #
  64. # ================================================= #
  65. SQL_DB_ENABLE: bool = True # 是否启用数据库
  66. DATABASE_ECHO: bool | Literal['debug'] = False # 是否显示SQL日志
  67. ECHO_POOL: bool | Literal['debug'] = False # 是否显示连接池日志
  68. POOL_SIZE: int = 10 # 连接池大小
  69. MAX_OVERFLOW: int = 20 # 最大溢出连接数
  70. POOL_TIMEOUT: int = 30 # 连接超时时间(秒)
  71. POOL_RECYCLE: int = 1800 # 连接回收时间(秒)
  72. POOL_USE_LIFO: bool = True # 是否使用LIFO连接池
  73. POOL_PRE_PING: bool = True # 是否开启连接预检
  74. FUTURE: bool = True # 是否使用SQLAlchemy 2.0特性
  75. AUTOCOMMIT: bool = False # 是否自动提交
  76. AUTOFETCH: bool = False # 是否自动刷新
  77. EXPIRE_ON_COMMIT: bool = False # 是否在提交时过期
  78. # 数据库类型
  79. DATABASE_TYPE: Literal['mysql', 'postgres'] = 'mysql'
  80. # MySQL/PostgreSQL数据库连接
  81. DATABASE_HOST: str = 'localhost'
  82. DATABASE_PORT: int = 3306
  83. DATABASE_USER: str = 'root'
  84. DATABASE_PASSWORD: str = 'ServBay.dev'
  85. DATABASE_NAME: str = 'fastapiadmin'
  86. # ================================================= #
  87. # ******************** Redis配置 ******************* #
  88. # ================================================= #
  89. REDIS_ENABLE: bool = True # 是否启用Redis
  90. REDIS_HOST: str = 'localhost'
  91. REDIS_PORT: int = 6379
  92. REDIS_DB_NAME: int = 1
  93. REDIS_USER: str = ''
  94. REDIS_PASSWORD: str = ''
  95. # ================================================= #
  96. # ******************** 验证码配置 ******************* #
  97. # ================================================= #
  98. CAPTCHA_ENABLE: bool = True # 是否启用验证码
  99. CAPTCHA_EXPIRE_SECONDS: int = 60 * 1 # 验证码过期时间(秒) 1分钟
  100. CAPTCHA_FONT_SIZE: int = 40 # 字体大小
  101. CAPTCHA_FONT_PATH: str = 'static/assets/font/Arial.ttf' # 字体路径
  102. # ================================================= #
  103. # ********************* 日志配置 ******************* #
  104. # ================================================= #
  105. OPERATION_LOG_RECORD: bool = True # 是否记录操作日志
  106. IGNORE_OPERATION_FUNCTION: List[str] = ["get_captcha_for_login"] # 忽略记录的函数
  107. OPERATION_RECORD_METHOD: List[str] = ["POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] # 需要记录的请求方法
  108. # ================================================= #
  109. # ******************* Gzip压缩配置 ******************* #
  110. # ================================================= #
  111. GZIP_ENABLE: bool = True # 是否启用Gzip
  112. GZIP_MIN_SIZE: int = 1000 # 最小压缩大小(字节)
  113. GZIP_COMPRESS_LEVEL: int = 9 # 压缩级别(1-9)
  114. # ================================================= #
  115. # ***************** 静态文件配置 ***************** #
  116. # ================================================= #
  117. STATIC_ENABLE: bool = True # 是否启用静态文件
  118. STATIC_URL: str = "/static" # 访问路由
  119. STATIC_DIR: str = "static" # 目录名
  120. STATIC_ROOT: Path = BASE_DIR.joinpath(STATIC_DIR) # 绝对路径
  121. # ================================================= #
  122. # ***************** 动态文件配置 ***************** #
  123. # ================================================= #
  124. UPLOAD_FILE_PATH: Path = Path('static/upload') # 上传目录
  125. UPLOAD_MACHINE: str = 'A' # 上传机器标识
  126. ALLOWED_EXTENSIONS: list[str] = [ # 允许的文件类型
  127. '.gif', '.jpg', '.jpeg', '.png', '.ico', '.svg', '.xls', '.xlsx'
  128. ]
  129. MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 最大文件大小(10MB)
  130. # ================================================= #
  131. # ***************** Swagger配置 ***************** #
  132. # ================================================= #
  133. SWAGGER_CSS_URL: str = "static/swagger/swagger-ui/swagger-ui.css"
  134. SWAGGER_JS_URL: str = "static/swagger/swagger-ui/swagger-ui-bundle.js"
  135. REDOC_JS_URL: str = "static/swagger/redoc/bundles/redoc.standalone.js"
  136. FAVICON_URL: str = "static/swagger/favicon.png"
  137. # ================================================= #
  138. # ******************* AI大模型配置 ****************** #
  139. # ================================================= #
  140. OPENAI_BASE_URL: str = ''
  141. OPENAI_API_KEY: str = ''
  142. OPENAI_MODEL: str = ''
  143. # ================================================= #
  144. # ******************* 请求限制配置 ****************** #
  145. # ================================================= #
  146. REQUEST_LIMITER_REDIS_PREFIX: str = 'fastapiadmin:request_limiter:'
  147. # ================================================= #
  148. # ******************* 重构配置 ******************* #
  149. # ================================================= #
  150. @property
  151. def MIDDLEWARE_LIST(self) -> List[Optional[str]]:
  152. """获取项目根目录"""
  153. # 中间件列表
  154. MIDDLEWARES: List[Optional[str]] = [
  155. "app.core.middlewares.CustomCORSMiddleware" if self.CORS_ORIGIN_ENABLE else None,
  156. "app.core.middlewares.RequestLogMiddleware" if self.OPERATION_LOG_RECORD else None,
  157. "app.core.middlewares.CustomGZipMiddleware" if self.GZIP_ENABLE else None,
  158. ]
  159. return MIDDLEWARES
  160. @property
  161. def EVENT_LIST(self) -> List[Optional[str]]:
  162. """获取事件列表"""
  163. EVENTS: List[Optional[str]] = [
  164. "app.core.database.redis_connect" if self.REDIS_ENABLE else None,
  165. ]
  166. return EVENTS
  167. @property
  168. def ASYNC_DB_URI(self) -> str:
  169. """获取异步数据库连接"""
  170. if self.DATABASE_TYPE == "mysql":
  171. return f"mysql+asyncmy://{self.DATABASE_USER}:{self.DATABASE_PASSWORD}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
  172. #return f"mysql+asyncmy://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
  173. elif self.DATABASE_TYPE == "postgres":
  174. return f"postgresql+asyncpg://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
  175. elif self.DATABASE_TYPE == "sqlite":
  176. return f"sqlite+aiosqlite:///{self.DATABASE_NAME}"
  177. elif self.DATABASE_TYPE == "dm":
  178. return f"dm+dmPython://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
  179. else:
  180. raise ValueError(f"数据库驱动不支持: {self.DATABASE_TYPE}, 请选择 请选择 mysql、postgres")
  181. @property
  182. def DB_URI(self) -> str:
  183. """获取同步数据库连接"""
  184. if self.DATABASE_TYPE == "mysql":
  185. return f"mysql+pymysql://{self.DATABASE_USER}:{self.DATABASE_PASSWORD}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
  186. #return f"mysql+pymysql://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
  187. elif self.DATABASE_TYPE == "postgres":
  188. return f"postgresql+psycopg2://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
  189. elif self.DATABASE_TYPE == "sqlite":
  190. return f"sqlite+pysqlite:///{self.DATABASE_NAME}"
  191. elif self.DATABASE_TYPE == "dm":
  192. return f"dm+dmPython://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
  193. else:
  194. raise ValueError(f"数据库驱动不支持: {self.DATABASE_TYPE}, 请选择 请选择 mysql、postgres")
  195. @property
  196. def REDIS_URI(self) -> str:
  197. """获取Redis连接"""
  198. return f"redis://{self.REDIS_USER}:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB_NAME}"
  199. @property
  200. def FASTAPI_CONFIG(self) -> dict[str, Any]:
  201. """获取FastAPI应用属性"""
  202. return {
  203. "debug": self.DEBUG,
  204. "title": self.TITLE,
  205. "version": self.VERSION,
  206. "description": self.DESCRIPTION,
  207. "summary": self.SUMMARY,
  208. "docs_url": None,
  209. "redoc_url": None,
  210. "root_path": self.ROOT_PATH
  211. }
  212. @lru_cache(maxsize=1)
  213. def get_settings() -> Settings:
  214. """获取配置实例"""
  215. return Settings()
  216. settings = get_settings()