Files
FastapiAdmin/backend/app/config/setting.py
T
zhangtao b0ae6af3b1 chore: update .gitignore and enhance docstrings across multiple files
- Added *.pyc and *.pyo to .gitignore to prevent compiled Python files from being tracked.
- Improved docstrings in various modules, providing clearer descriptions of functions, parameters, and return values to enhance code readability and maintainability.
2026-04-04 01:21:59 +08:00

326 lines
13 KiB
Python
Executable File

import os
from functools import lru_cache
from pathlib import Path
from typing import Any, Literal
from urllib.parse import quote_plus
from pydantic_settings import BaseSettings, SettingsConfigDict
from app.common.enums import EnvironmentEnum
from app.config.path_conf import BASE_DIR, ENV_DIR
class Settings(BaseSettings):
"""系统配置类"""
model_config = SettingsConfigDict(
env_file=ENV_DIR / f".env.{os.getenv('ENVIRONMENT')}",
env_file_encoding="utf-8",
extra="ignore",
case_sensitive=True, # 区分大小写
)
# ================================================= #
# ******************* 项目环境 ****************** #
# ================================================= #
ENVIRONMENT: EnvironmentEnum = EnvironmentEnum.DEV
# ================================================= #
# ******************* 服务器配置 ****************** #
# ================================================= #
SERVER_HOST: str = "0.0.0.0" # 允许访问的IP地址
SERVER_PORT: int = 8001 # 服务端口
# ================================================= #
# ******************* API文档配置 ****************** #
# ================================================= #
DEBUG: bool = True # 调试模式
TITLE: str = "🎉 FastapiAdmin 🎉 " # 文档标题
VERSION: str = "0.1.0" # 版本号
DESCRIPTION: str = (
"该项目是一个基于python的web服务框架,基于fastapi和sqlalchemy实现。" # 文档描述
)
SUMMARY: str = "接口汇总" # 文档概述
DOCS_URL: str = "/docs" # Swagger UI路径
REDOC_URL: str = "/redoc" # ReDoc路径
LJDOC_URL: str = "/ljdoc" # LangJin UI路径
ROOT_PATH: str = "/api/v1" # API路由前缀
# ================================================= #
# ******************** 日志配置 ******************** #
# ================================================= #
LOGGER_LEVEL: str = "DEBUG" # 日志级别
# ================================================= #
# ******************** 跨域配置 ******************** #
# ================================================= #
CORS_ORIGIN_ENABLE: bool = True # 是否启用跨域
ALLOW_ORIGINS: list[str] = ["*"] # 允许的域名列表
ALLOW_METHODS: list[str] = ["*"] # 允许的HTTP方法
ALLOW_HEADERS: list[str] = ["*"] # 允许的请求头
ALLOW_CREDENTIALS: bool = True # 是否允许携带cookie
CORS_EXPOSE_HEADERS: list[str] = ["X-Request-ID"]
# ================================================= #
# ******************* 登录认证配置 ****************** #
# ================================================= #
SECRET_KEY: str = "vgb0tnl9d58+6n-6h-ea&u^1#s0ccp!794=krylxcjq75vzps$" # JWT密钥
ALGORITHM: str = "HS256" # JWT算法
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 30 # access_token过期时间(秒)30 分钟
REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 30 # refresh_token过期时间(秒)30 分钟
TOKEN_TYPE: str = "bearer" # token类型
TOKEN_REQUEST_PATH_EXCLUDE: list[str] = ["api/v1/auth/login"] # JWT / RBAC 路由白名单
TOKEN_SLIDING_EXPIRE: bool = True # 是否启用滑动过期(用户操作时自动续期)
# ================================================= #
# ******************** 数据库配置 ******************* #
# ================================================= #
SQL_DB_ENABLE: bool = True # 是否启用数据库
DATABASE_ECHO: bool | Literal["debug"] = False # 是否显示SQL日志
ECHO_POOL: bool | Literal["debug"] = False # 是否显示连接池日志
POOL_SIZE: int = 10 # 连接池大小
MAX_OVERFLOW: int = 20 # 最大溢出连接数
POOL_TIMEOUT: int = 30 # 连接超时时间(秒)
POOL_RECYCLE: int = 1800 # 连接回收时间(秒)
POOL_USE_LIFO: bool = True # 是否使用LIFO连接池
POOL_PRE_PING: bool = True # 是否开启连接预检
FUTURE: bool = True # 是否使用SQLAlchemy 2.0特性
AUTOCOMMIT: bool = False # 是否自动提交
AUTOFETCH: bool = False # 是否自动刷新
EXPIRE_ON_COMMIT: bool = False # 是否在提交时过期
# MySQL/PostgreSQL数据库连接
DATABASE_TYPE: Literal["mysql", "postgres", "sqlite"] = "mysql"
DATABASE_HOST: str = "localhost"
DATABASE_PORT: int = 3306
DATABASE_USER: str = "root"
DATABASE_PASSWORD: str = "ServBay.dev"
DATABASE_NAME: str = "fastapiadmin"
# ================================================= #
# ******************** Redis配置 ******************* #
# ================================================= #
REDIS_ENABLE: bool = True # 是否启用Redis
REDIS_HOST: str = "localhost"
REDIS_PORT: int = 6379
REDIS_DB_NAME: int = 1
REDIS_USER: str = ""
REDIS_PASSWORD: str = ""
# ================================================= #
# ******************** 验证码配置 ******************* #
# ================================================= #
CAPTCHA_ENABLE: bool = True # 是否启用验证码
CAPTCHA_EXPIRE_SECONDS: int = 60 * 1 # 验证码过期时间(秒) 1分钟
CAPTCHA_FONT_SIZE: int = 35 # 字体大小
CAPTCHA_FONT_PATH: str = "static/assets/font/Arial.ttf" # 字体路径
# 是否请求外网解析 IP 归属地(登录发 token、操作日志写 login_location 共用;关闭可明显加快登录)
LOGIN_RESOLVE_IP_LOCATION: bool = False
# ================================================= #
# ********************* 日志配置 ******************* #
# ================================================= #
OPERATION_LOG_RECORD: bool = True # 是否记录操作日志
IGNORE_OPERATION_FUNCTION: list[str] = ["get_captcha_for_login"] # 忽略记录的函数
OPERATION_RECORD_METHOD: list[str] = [
"POST",
"PUT",
"PATCH",
"DELETE",
"HEAD",
"OPTIONS",
] # 需要记录的请求方法
# ================================================= #
# ******************* Gzip压缩配置 ******************* #
# ================================================= #
GZIP_ENABLE: bool = True # 是否启用Gzip
GZIP_MIN_SIZE: int = 1000 # 最小压缩大小(字节)
GZIP_COMPRESS_LEVEL: int = 9 # 压缩级别(1-9)
# ================================================= #
# ***************** 静态文件配置 ***************** #
# ================================================= #
STATIC_ENABLE: bool = True # 是否启用静态文件
STATIC_URL: str = "/static" # 访问路由
STATIC_DIR: str = "static" # 目录名
STATIC_ROOT: Path = BASE_DIR.joinpath(STATIC_DIR) # 绝对路径
# ================================================= #
# ***************** 动态文件配置 ***************** #
# ================================================= #
UPLOAD_FILE_PATH: Path = Path("static/upload") # 上传目录
UPLOAD_MACHINE: str = "A" # 上传机器标识
ALLOWED_EXTENSIONS: list[str] = [ # 允许的文件类型
".gif",
".jpg",
".jpeg",
".png",
".ico",
".svg",
".xls",
".xlsx",
]
MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 最大文件大小(10MB)
# ================================================= #
# ***************** Swagger配置 ***************** #
# ================================================= #
SWAGGER_CSS_URL: str = "static/swagger/swagger-ui/swagger-ui.css"
SWAGGER_JS_URL: str = "static/swagger/swagger-ui/swagger-ui-bundle.js"
REDOC_JS_URL: str = "static/swagger/redoc/bundles/redoc.standalone.js"
CUSTOM_CSS_URL: str = "static/swagger/custom-ui/styles.css"
CUSTOM_JS_URL: str = "static/swagger/custom-ui/scripts.js"
FAVICON_URL: str = "static/swagger/favicon.png"
# ================================================= #
# ******************* AI大模型配置 ****************** #
# ================================================= #
OPENAI_BASE_URL: str = ""
OPENAI_API_KEY: str = ""
OPENAI_MODEL: str = ""
# ================================================= #
# ******************* ChromaDB配置 ****************** #
# ================================================= #
CHROMA_PERSIST_DIR: str = str(BASE_DIR / "data" / "chroma") # ChromaDB 持久化目录
CHROMA_COLLECTION_NAME: str = "knowledge_base" # ChromaDB 集合名称
# ================================================= #
# ******************* 请求限制配置 ****************** #
# ================================================= #
REQUEST_LIMITER_REDIS_PREFIX: str = "fastapiadmin:request_limiter:"
# ================================================= #
# ******************* 重构配置 ******************* #
# ================================================= #
@property
def MIDDLEWARE_LIST(self) -> list[str | None]:
"""
根据开关组装的中间件类路径列表(未启用的项为 None)。
返回:
- list[str | None]: 中间件 import 路径或 None。
"""
# 中间件列表
MIDDLEWARES: list[str | None] = [
"app.core.middlewares.CustomCORSMiddleware" if self.CORS_ORIGIN_ENABLE else None,
"app.core.middlewares.RequestLogMiddleware" if self.OPERATION_LOG_RECORD else None,
"app.core.middlewares.CustomGZipMiddleware" if self.GZIP_ENABLE else None,
]
return MIDDLEWARES
@property
def EVENT_LIST(self) -> list[str | None]:
"""
应用启动时加载的全局异步事件模块路径列表。
返回:
- list[str | None]: 事件模块路径或 None。
"""
EVENTS: list[str | None] = [
"app.core.database.redis_connect" if self.REDIS_ENABLE else None,
]
return EVENTS
@property
def ASYNC_DB_URI(self) -> str:
"""
异步 SQLAlchemy 数据库 URL。
返回:
- str: 异步驱动连接串。
异常:
- ValueError: 数据库类型不支持时抛出。
"""
if self.DATABASE_TYPE not in ("mysql", "postgres", "sqlite"):
raise ValueError(
f"数据库驱动不支持: {self.DATABASE_TYPE}, 异步数据库请选择 mysql、postgres、sqlite"
)
db_connect: str = ""
if self.DATABASE_TYPE == "mysql":
db_connect = f"mysql+asyncmy://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
elif self.DATABASE_TYPE == "postgres":
db_connect = f"postgresql+asyncpg://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
else:
db_connect = f"sqlite+aiosqlite:///{self.DATABASE_NAME}.db"
return db_connect
@property
def DB_URI(self) -> str:
"""
同步 SQLAlchemy 数据库 URL。
返回:
- str: 同步驱动连接串。
异常:
- ValueError: 数据库类型不支持时抛出。
"""
if self.DATABASE_TYPE not in ("mysql", "postgres", "sqlite"):
raise ValueError(
f"数据库驱动不支持: {self.DATABASE_TYPE}, 同步数据库请选择 mysql、postgres、sqlite"
)
db_connect: str = ""
if self.DATABASE_TYPE == "mysql":
db_connect = f"mysql+pymysql://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}?charset=utf8mb4"
elif self.DATABASE_TYPE == "postgres":
db_connect = f"postgresql+psycopg://{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}"
else:
db_connect = f"sqlite:///{self.DATABASE_NAME}.db"
return db_connect
@property
def REDIS_URI(self) -> str:
"""
Redis 连接 URL。
返回:
- str: redis:// 连接串。
"""
return f"redis://{self.REDIS_USER}:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB_NAME}"
@property
def FASTAPI_CONFIG(self) -> dict[str, Any]:
"""
创建 FastAPI 应用实例时使用的关键字参数子集。
返回:
- dict[str, Any]: debug、title、responses 等配置。
"""
return {
"debug": self.DEBUG,
"title": self.TITLE,
"version": self.VERSION,
"description": self.DESCRIPTION,
"summary": self.SUMMARY,
"docs_url": None,
"redoc_url": None,
"root_path": self.ROOT_PATH,
"responses": {
200: {"description": "成功"},
400: {"description": "请求参数错误"},
401: {"description": "未认证"},
403: {"description": "未授权"},
404: {"description": "资源不存在"},
422: {"description": "请求参数验证错误"},
500: {"description": "服务器内部错误"},
},
}
@lru_cache(maxsize=1)
def get_settings() -> Settings:
"""
获取全局 Settings 单例(lru_cache 缓存)。
返回:
- Settings: 配置实例。
"""
return Settings()
settings = get_settings()