📅 今日知识点
- 核心主题:使用Pydantic管理应用配置、环境变量解析、配置验证、多环境配置切换
- 适用场景:Web应用配置管理、微服务配置中心、CLI工具参数管理、十二要素应用配置实践
- 一句话总结:Pydantic配置管理让配置验证自动化,环境变量无缝集成,告别配置错误和类型问题
🧩 核心原理(简化版)
- Pydantic的BaseSettings类专为配置管理设计,自动从环境变量加载配置
- 核心逻辑:定义配置模型类,并使其继承自BaseSettings,其字段便会自动映射环境变量,内置类型验证和默认值处理
- 核心价值:统一配置入口、自动类型转换、环境隔离、配置文档自动生成
💻 代码实战
1. 安装依赖
bash
pip install pydantic[dotenv] # 包含dotenv支持
2. 环境配置文件
env
# 创建环境文件.env,包含以下内容:
APP_NAME=MyAwesomeApp1
DEBUG=true
VERSION=1.0.1
API_KEYS=["key1","key2","key3"]
DB_HOST=127.0.0.1
DB_PORT=54321
DB_USERNAME=user
DB_PASSWORD=pass
DB_NAME=pass
REDIS_HOST=127.0.0.1
REDIS_PORT=6371
REDIS_PASSWORD=123456
REDIS_DB=0
3. 基础配置管理类示例
python
from pathlib import Path
from typing import List, Optional
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings
# 数据库配置
class DatabaseSettings(BaseSettings):
"""数据库配置"""
host: str = Field(default="localhost", alias="DB_HOST")
port: int = Field(default=5432, alias="DB_PORT")
# Make individual parts optional; allow providing a full DATABASE_URL instead
username: Optional[str] = Field(default=None, alias="DB_USERNAME")
password: Optional[str] = Field(default=None, alias="DB_PASSWORD")
database: Optional[str] = Field(default=None, alias="DB_NAME")
database_url: Optional[str] = Field(default=None, alias="DATABASE_URL")
# 数据库URL构建
@property
def url(self) -> str:
# If a full DATABASE_URL was provided, prefer that
if self.database_url:
return self.database_url
# Fallback to building from parts (use empty strings for missing values)
user = self.username or ""
pwd = self.password or ""
db = self.database or ""
return f"postgresql://{user}:{pwd}@{self.host}:{self.port}/{db}"
model_config = {
"env_prefix": "DB_", # 环境变量前缀
"extra": "ignore", # 忽略未定义字段
"case_sensitive": False, # 环境变量不区分大小写
"env_file": ".env", # 环境变量文件配置
"env_file_encoding": "utf-8"
}
# Redis配置
class RedisSettings(BaseSettings):
"""Redis配置"""
host: str = "localhost"
port: int = 6379
password: Optional[str] = None
db: int = 0
model_config = {
"env_prefix": "REDIS_",
"extra": "ignore", # 忽略未定义字段
"case_sensitive": False, # 环境变量不区分大小写
"env_file": ".env", # 环境变量文件配置
"env_file_encoding": "utf-8"
}
# 包含数据库和redis配置的主应用配置
class AppSettings(BaseSettings):
"""应用主配置"""
app_name: str = "MyApp"
debug: bool = False
version: str = "1.0.0"
# 嵌套配置 - 使用工厂函数延迟初始化
database: DatabaseSettings = Field(default_factory=DatabaseSettings)
redis: RedisSettings = Field(default_factory=RedisSettings)
# 复杂类型配置
# Store the raw env value (string) and parse it into a Python list via a
# property. This avoids pydantic-settings attempting to JSON-decode a
# List[str] field from a comma-separated .env value.
api_keys: Optional[str] = Field(default=None, alias="API_KEYS")
allowed_hosts: List[str] = ["localhost"]
log_level: str = "INFO"
# 路径配置
data_dir: Path = Field(default=Path("./data"))
temp_dir: Path = Field(default=Path("./temp"))
# 自定义验证
@field_validator('log_level')
@classmethod
def validate_log_level(cls, v):
# Ensure we accept None or empty values and normalize to upper-case
if v is None:
return "INFO"
if isinstance(v, str):
valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
if v.upper() not in valid_levels:
raise ValueError(f'日志级别必须是: {valid_levels}')
return v.upper()
raise ValueError('log_level must be a string')
model_config = {
# 环境变量文件配置
"env_file": ".env",
"env_file_encoding": "utf-8",
# 允许通过字段名而不是别名填充
"case_sensitive": False,
"extra": "ignore" # 忽略未定义字段
}
4. 测试
python
def main():
try:
# 加载配置
settings = AppSettings()
print("✅ 配置加载成功!")
print(f"应用名称: {settings.app_name}")
print(f"调试模式: {settings.debug}")
print(f"数据库URL: {settings.database.url}")
print(f"Redis地址: {settings.redis.host}:{settings.redis.port}")
print(f"API密钥数量: {len(settings.api_keys)}")
print(f"API密钥列表: {settings.api_keys}")
print(f"数据目录: {settings.data_dir.absolute()}")
print(f"日志级别: {settings.log_level}")
# 验证路径存在
settings.data_dir.mkdir(exist_ok=True)
settings.temp_dir.mkdir(exist_ok=True)
print("📁 目录创建完成")
except Exception as e:
import traceback
print(f"❌ 配置加载失败: {e!r}")
traceback.print_exc()
print("请检查:")
print("1. .env 文件是否存在且格式正确")
print("2. 必需的环境变量是否已设置")
print("3. API_KEYS 是否为逗号分隔的字符串")
if __name__ == "__main__":
main()
运行结果:
text
✅ 配置加载成功!
应用名称: MyAwesomeApp1
调试模式: True
数据库URL: postgresql://user:pass@127.0.0.1:54321/pass
Redis地址: 127.0.0.1:6371
API密钥数量: 22
API密钥列表: ["key1","key2","key3"]
数据目录: D:\Gitee\TechLearn\learn-python\code\basic\data
日志级别: INFO
📁 目录创建完成
✅ 今日总结
- Pydantic配置管理核心是"声明即配置",通过类型系统自动完成验证和转换
- 关键要点:BaseSettings继承、环境变量映射、嵌套配置、类型安全
- 实战价值:统一配置管理、减少配置错误