#Pydantic Settings:多环境配置文件(开发/测试/生产)管理
📂 所属阶段:第五阶段 — 工程化与部署(实战篇)
🔗 相关章节:依赖注入系统 · FastAPI 进阶
#1. 为什么需要环境配置管理?
#1.1 问题场景
# ❌ 硬编码配置(开发/测试/生产混在一起)
DATABASE_URL = "postgresql://localhost:5432/mydb"
SECRET_KEY = "dev-secret-key"
DEBUG = True
# 上线时手动改?容易出错!#1.2 正确方案
.env(本地) .env.test(测试) .env.production(生产)
───────────────── ───────────────── ─────────────────
DATABASE_URL=... DATABASE_URL=... DATABASE_URL=...
SECRET_KEY=dev-... SECRET_KEY=test-... SECRET_KEY=生产密钥
DEBUG=true DEBUG=false DEBUG=false
LOG_LEVEL=debug LOG_LEVEL=info LOG_LEVEL=warning#2. Pydantic Settings 基础
#2.1 安装
pip install pydantic-settings
# Pydantic v2 已内置,只需安装#2.2 基础配置
# config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
class Settings(BaseSettings):
"""应用配置"""
model_config = SettingsConfigDict(
env_file=".env", # 读取 .env 文件
env_file_encoding="utf-8",
case_sensitive=False, # 环境变量大小写不敏感
extra="ignore", # 忽略额外字段
)
# 应用信息
app_name: str = "DaomanAPI"
version: str = "1.0.0"
debug: bool = False
# 数据库
database_url: str = "sqlite+aiosqlite:///./app.db"
# JWT
jwt_secret: str = "change-me-in-production"
jwt_algorithm: str = "HS256"
jwt_expire_minutes: int = 30
jwt_refresh_expire_days: int = 30
# Redis
redis_url: str = "redis://localhost:6379/0"
# CORS
cors_origins: list[str] = ["http://localhost:3000"]
# 日志
log_level: str = "INFO"
@property
def is_production(self) -> bool:
return self.environment == "production"
@lru_cache()
def get_settings() -> Settings:
"""单例模式,全局复用同一份配置"""
return Settings()#3. 环境隔离
#3.1 按环境加载不同 .env
# config.py
import os
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=f".env.{os.getenv('ENV', 'development')}", # 关键!
)
# 根据 ENV 变量自动加载 .env.development / .env.production# .env.development
ENV=development
DATABASE_URL=sqlite+aiosqlite:///./dev.db
DEBUG=true
LOG_LEVEL=debug
# .env.production
ENV=production
DATABASE_URL=postgresql+asyncpg://user:pass@db.example.com/myapp
DEBUG=false
LOG_LEVEL=warning
JWT_SECRET=你的超长随机密钥(至少32字符)
# .env.test
ENV=test
DATABASE_URL=sqlite+aiosqlite:///./test.db#3.2 启动命令隔离
# 开发环境
uvicorn main:app --reload
# 测试环境
ENV=test pytest tests/
# 生产环境
ENV=production uvicorn main:app --host 0.0.0.0 --port 8000#4. 敏感信息管理
#4.1 生产环境:环境变量优先
# 生产环境:环境变量(K8s / Docker Secret / 云平台管理)
# 导出到系统环境变量,优先级高于 .env 文件
# os.environ["JWT_SECRET"] = "从云平台读取"
class Settings(BaseSettings):
# 如果系统环境变量存在,覆盖 .env 中的值
jwt_secret: str = "default-fallback"#4.2 Docker 环境变量
# docker run -e JWT_SECRET="生产密钥" -e DATABASE_URL="postgresql://..."
docker run -d \
-e ENV=production \
-e JWT_SECRET="$(openssl rand -base64 32)" \
-p 8000:8000 \
my-fastapi-app#5. 在 FastAPI 中使用
#5.1 主应用配置
# main.py
from fastapi import FastAPI
from config import get_settings
settings = get_settings()
app = FastAPI(
title=settings.app_name,
version=settings.version,
debug=settings.debug,
)
# 日志配置
import logging
logging.basicConfig(level=settings.log_level)
# 路由注册、数据库初始化...#5.2 依赖注入配置
# dependencies.py
from functools import lru_cache
@lru_cache
def get_settings() -> Settings:
return Settings()
# 路由中使用
@app.get("/config")
async def show_config(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"debug": settings.debug,
# 不返回敏感字段!
}#6. 完整配置结构
# .env.development 示例
ENV=development
APP_NAME=DaomanAPI
VERSION=1.0.0
DEBUG=true
# 数据库
DATABASE_URL=sqlite+aiosqlite:///./data/dev.db
# Redis
REDIS_URL=redis://localhost:6379/0
# JWT(仅开发用简单密钥)
JWT_SECRET=dev-only-secret-key-not-for-production
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=60
# CORS
CORS_ORIGINS=["http://localhost:3000","http://localhost:8080"]
# 外部服务
GITHUB_CLIENT_ID=dev_client_id
GITHUB_CLIENT_SECRET=dev_client_secret
# 日志
LOG_LEVEL=debug#7. 小结
# 三分钟上手 Pydantic Settings
# 1. 安装
pip install pydantic-settings
# 2. 定义配置类
class Settings(BaseSettings):
app_name: str = "MyApp"
jwt_secret: str = "change-me"
# 3. 读取环境变量和 .env 文件
settings = Settings()
# 4. 在 FastAPI 中使用
@app.get("/")
async def root(settings: Settings = Depends(get_settings)):
return {"name": settings.app_name}💡 最佳实践:所有配置项只定义在
Settings类中一处,不要在代码里写死任何可变值(包括 DEBUG、数据库 URL 等)。这样测试时切换环境只需改环境变量。
🔗 扩展阅读

