fastapi-demo/app/core/config.py

144 lines
4.0 KiB
Python

"""
应用配置管理
支持从环境变量和 .env 文件加载配置
"""
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"
# === 数据库配置 ===
DATABASE_URL: Optional[str] = None
DB_ECHO: bool = False
DB_POOL_SIZE: int = 5
DB_MAX_OVERFLOW: int = 10
# === 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_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()