# settings.py # 统一配置入口:所有可变参数都从环境变量 / .env 读取,代码里不再出现硬编码密码。 # # 真实业务里"配置"和"代码"必须分离: # 开发 / 测试 / 生产 用的是三套数据库,靠改代码切环境一定会出事故。 import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent def _load_dotenv(path: Path) -> None: """极简 .env 加载器。 优先使用 python-dotenv;没装则用内置的简易解析,保证零依赖也能跑。 """ if not path.exists(): return try: from dotenv import load_dotenv # type: ignore load_dotenv(path, override=False) return except ImportError: pass for raw in path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, _, value = line.partition("=") key, value = key.strip(), value.strip().strip('"').strip("'") # 已存在的真实环境变量优先,不被文件覆盖 os.environ.setdefault(key, value) _load_dotenv(BASE_DIR / ".env") def _env(key: str, default: str) -> str: value = os.getenv(key) return default if value is None or value == "" else value def _env_bool(key: str, default: bool) -> bool: return _env(key, str(default)).strip().lower() in ("1", "true", "yes", "on") def _env_int(key: str, default: int) -> int: try: return int(_env(key, str(default))) except ValueError: return default class Settings: # ---------- 应用 ---------- APP_NAME: str = _env("APP_NAME", "学生管理系统") APP_VERSION: str = _env("APP_VERSION", "1.1.0") DEBUG: bool = _env_bool("DEBUG", True) HOST: str = _env("HOST", "127.0.0.1") PORT: int = _env_int("PORT", 8004) # API 统一前缀。改这里就能整体换版本,不用一个个改路由。 API_PREFIX: str = _env("API_PREFIX", "/api/v1") # ---------- 跨域 ---------- # 注意:allow_credentials=True 时浏览器【禁止】返回 "*", # 必须显式列出前端域名,否则带 Cookie / 登录态一定失败。 CORS_ORIGINS: list[str] = [ o.strip() for o in _env( "CORS_ORIGINS", "http://localhost:5500,http://127.0.0.1:5500," "http://localhost:8000,http://127.0.0.1:8000," "http://localhost:5173,http://127.0.0.1:5173", ).split(",") if o.strip() ] # ---------- 数据库 ---------- DB_HOST: str = _env("DB_HOST", "127.0.0.1") DB_PORT: int = _env_int("DB_PORT", 3306) DB_USER: str = _env("DB_USER", "root") DB_PASSWORD: str = _env("DB_PASSWORD", "") DB_NAME: str = _env("DB_NAME", "student_management_system") DB_CHARSET: str = _env("DB_CHARSET", "utf8mb4") DB_ECHO: bool = _env_bool("DB_ECHO", False) DB_POOL_SIZE: int = _env_int("DB_POOL_SIZE", 5) DB_MAX_OVERFLOW: int = _env_int("DB_MAX_OVERFLOW", 10) DB_POOL_RECYCLE: int = _env_int("DB_POOL_RECYCLE", 3600) @property def database_url(self) -> str: from urllib.parse import quote_plus return ( f"mysql+pymysql://{self.DB_USER}:{quote_plus(self.DB_PASSWORD)}" f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" f"?charset={self.DB_CHARSET}" ) settings = Settings()