""" 应用配置管理 支持从环境变量和 .env.dev 文件加载配置 """ from typing import List, Optional from pydantic import Field, validator from pydantic_settings import BaseSettings class Settings(BaseSettings): """应用配置类""" # === 应用基础配置 === PROJECT_NAME: str = "FastAPI Demo" VERSION: str = "1.0.0" DESCRIPTION: str = "A simple FastAPI learning project" DEBUG: bool = False ENVIRONMENT: str = Field(default="production", description="运行环境: development, testing, production") # === 服务器配置 === HOST: str = "127.0.0.1" PORT: int = 8000 WORKERS: int = 1 RELOAD: bool = False LOG_LEVEL: str = "info" # === API 配置 === API_V1_STR: str = "/api/v1" DOCS_URL: Optional[str] = "/docs" REDOC_URL: Optional[str] = "/redoc" # === 数据库配置 === # MySQL 数据库配置(从环境变量或 .env 文件读取) DB_HOST: str = Field(default="localhost", description="数据库主机地址") DB_PORT: int = Field(default=3306, description="数据库端口") DB_USER: str = Field(default="root", description="数据库用户名") DB_PASSWORD: str = Field(default="", description="数据库密码") DB_NAME: str = Field(default="fastapi_demo", description="数据库名称") DB_CHARSET: str = Field(default="utf8mb4", description="数据库字符集") # 数据库连接池配置 DB_ECHO: bool = False DB_POOL_SIZE: int = 5 DB_MAX_OVERFLOW: int = 10 DB_POOL_TIMEOUT: int = 30 DB_POOL_RECYCLE: int = 3600 @property def DATABASE_URL(self) -> str: """构建数据库连接URL""" return f"mysql+pymysql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}?charset={self.DB_CHARSET}" # === Redis 配置 === REDIS_HOST: str = "localhost" REDIS_PORT: int = 6379 REDIS_DB: int = 0 REDIS_PASSWORD: Optional[str] = None # === CORS 配置 === CORS_ORIGINS: List[str] = ["*"] CORS_ALLOW_CREDENTIALS: bool = True CORS_ALLOW_METHODS: List[str] = ["*"] CORS_ALLOW_HEADERS: List[str] = ["*"] # === JWT 认证配置 === SECRET_KEY: str = Field(default="your-secret-key-change-in-production", min_length=32) ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 REFRESH_TOKEN_EXPIRE_DAYS: int = 7 # === 邮件配置 === SMTP_HOST: Optional[str] = None SMTP_PORT: int = 587 SMTP_USER: Optional[str] = None SMTP_PASSWORD: Optional[str] = None SMTP_FROM: Optional[str] = None # === 文件上传配置 === UPLOAD_DIR: str = "./uploads" MAX_UPLOAD_SIZE: int = 10485760 # 10MB ALLOWED_EXTENSIONS: List[str] = ["jpg", "jpeg", "png", "pdf", "doc", "docx"] # === 第三方 API 配置 === OPENAI_API_KEY: Optional[str] = None STRIPE_API_KEY: Optional[str] = None AWS_ACCESS_KEY_ID: Optional[str] = None AWS_SECRET_ACCESS_KEY: Optional[str] = None AWS_REGION: str = "us-east-1" # === 监控配置 === SENTRY_DSN: Optional[str] = None PROMETHEUS_ENABLED: bool = False METRICS_PATH: str = "/metrics" # === 限流配置 === RATE_LIMIT_ENABLED: bool = True RATE_LIMIT_REQUESTS: int = 100 RATE_LIMIT_PERIOD: int = 60 # seconds @validator("ENVIRONMENT") def validate_environment(cls, v): """验证运行环境""" allowed = ["development", "testing", "production"] if v not in allowed: raise ValueError(f"ENVIRONMENT must be one of {allowed}") return v @validator("CORS_ORIGINS", pre=True) def parse_cors_origins(cls, v): """解析 CORS 来源配置""" if isinstance(v, str): return [origin.strip() for origin in v.split(",")] return v @property def is_development(self) -> bool: """是否为开发环境""" return self.ENVIRONMENT == "development" @property def is_production(self) -> bool: """是否为生产环境""" return self.ENVIRONMENT == "production" @property def is_testing(self) -> bool: """是否为测试环境""" return self.ENVIRONMENT == "testing" class Config: env_file = ".env" env_file_encoding = "utf-8" case_sensitive = True # 根据环境加载不同的配置文件 def get_settings() -> Settings: """获取配置实例""" import os env = os.getenv("ENVIRONMENT", "development") # 优先级:环境特定配置 > .env 通用配置 env_files = [".env"] if env == "development": env_files.append(".env.dev") elif env == "testing": env_files.append(".env.test") elif env == "production": env_files.append(".env.prod") # 尝试加载对应的环境配置文件 for env_file in reversed(env_files): if os.path.exists(env_file): return Settings(_env_file=env_file) return Settings() # 全局配置实例 settings = get_settings()