Pydantic Settings 配置管理¶
为什么要学 Pydantic Settings¶
Pydantic Settings 是一个基于 Pydantic 的应用配置管理库。它能从环境变量、.env 文件、JSON/YAML 配置文件等多种来源加载配置,并自动进行类型验证和转换。与手动解析 os.environ 相比,Pydantic Settings 提供了类型安全、自动校验、IDE 补全和文档化的配置管理方式。对于任何 Python 应用的配置管理来说,这是最现代和最可靠的方案。
核心概念¶
| 概念 | 白话解释 | 用途 |
|---|---|---|
| BaseSettings | 设置基类 | 所有配置类的父类 |
| Environment Variables | 环境变量 | 从系统环境读取配置 |
| .env File | 环境文件 | 从文件加载配置 |
| Validators | 验证器 | 自定义验证逻辑 |
| Nested Models | 嵌套模型 | 结构化的配置组 |
| Field | 字段 | 配置项定义 |
安装配置¶
pip install pydantic-settings
# 支持 .env 文件
pip install pydantic-settings[dotenv]
# 支持 YAML/TOML
pip install pydantic-settings[yaml,toml]
快速上手¶
基本使用¶
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "MyApp"
debug: bool = False
database_url: str
redis_url: str = "redis://localhost:6379"
api_key: str
model_config = {
"env_file": ".env",
"env_file_encoding": "utf-8",
}
# .env 文件:
# DATABASE_URL=postgresql://user:pass@localhost/db
# API_KEY=sk-xxx
settings = Settings()
print(settings.database_url) # postgresql://user:pass@localhost/db
print(settings.debug) # False
类型自动转换¶
class Settings(BaseSettings):
port: int = 8000 # "8000" → 8000
debug: bool = False # "true" → True
hosts: list[str] = [] # '["a","b"]' → ["a", "b"]
timeout: float = 30.0 # "30.0" → 30.0
model_config = {"env_file": ".env"}
嵌套配置¶
from pydantic import BaseModel
class DatabaseSettings(BaseModel):
host: str = "localhost"
port: int = 5432
name: str = "mydb"
user: str = "admin"
password: str
class RedisSettings(BaseModel):
host: str = "localhost"
port: int = 6379
db: int = 0
class Settings(BaseSettings):
app_name: str = "MyApp"
database: DatabaseSettings
redis: RedisSettings
model_config = {
"env_nested_delimiter": "__",
"env_file": ".env",
}
# 环境变量:
# DATABASE__HOST=db.example.com
# DATABASE__PASSWORD=secret
# REDIS__PORT=6380
进阶用法¶
自定义验证¶
from pydantic import field_validator, model_validator
class Settings(BaseSettings):
database_url: str
api_key: str
log_level: str = "INFO"
@field_validator("log_level")
@classmethod
def validate_log_level(cls, v):
allowed = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
if v.upper() not in allowed:
raise ValueError(f"log_level must be one of {allowed}")
return v.upper()
@field_validator("api_key")
@classmethod
def validate_api_key(cls, v):
if not v.startswith("sk-"):
raise ValueError("API key must start with 'sk-'")
return v
@model_validator(mode="after")
def validate_model(self):
if self.log_level == "DEBUG" and "prod" in self.database_url:
raise ValueError("Cannot use DEBUG log level with production database")
return self
多环境配置¶
from pydantic_settings import BaseSettings
from typing import Literal
class Settings(BaseSettings):
environment: Literal["development", "staging", "production"] = "development"
debug: bool = False
database_url: str
model_config = {
"env_file": (".env", ".env.local"), # 多文件,后者覆盖前者
}
class DevSettings(Settings):
debug: bool = True
database_url: str = "sqlite:///dev.db"
class ProdSettings(Settings):
debug: bool = False
model_config = {
"env_file": ".env.production",
}
def get_settings():
env = os.getenv("ENVIRONMENT", "development")
if env == "production":
return ProdSettings()
return DevSettings()
YAML/TOML 配置源¶
from pydantic_settings import BaseSettings, YamlConfigSettingsSource
class Settings(BaseSettings):
app_name: str
debug: bool = False
@classmethod
def settings_customise_sources(cls, settings_cls, **kwargs):
return (
# 优先级从高到低
kwargs.get("env_settings", ()),
kwargs.get("dotenv_settings", ()),
YamlConfigSettingsSource(settings_cls, yaml_file="config.yaml"),
kwargs.get("init_settings", ()),
)
FastAPI 集成¶
from fastapi import FastAPI, Depends
from functools import lru_cache
class Settings(BaseSettings):
app_name: str = "My API"
admin_email: str
database_url: str
model_config = {"env_file": ".env"}
@lru_cache
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
}
敏感字段¶
from pydantic import SecretStr
class Settings(BaseSettings):
api_key: SecretStr
database_password: SecretStr
model_config = {"env_file": ".env"}
settings = Settings()
print(settings.api_key) # SecretStr('**********')
print(settings.api_key.get_secret_value()) # 实际值
print(settings.model_dump()) # api_key 显示为 **********
常见问题¶
Q: 环境变量名的规则?¶
默认将字段名转为大写作为环境变量名。可通过 env_prefix 添加前缀:
Q: 配置优先级是什么?¶
默认优先级(高到低): 1. __init__ 参数 2. 环境变量 3. .env 文件 4. 默认值
Q: 如何在测试中覆盖配置?¶
def test_something():
settings = Settings(database_url="sqlite:///test.db", api_key="sk-test")
# 或
with mock.patch.dict(os.environ, {"DATABASE_URL": "sqlite:///test.db"}):
settings = Settings()
参考资源¶
- 文档:https://docs.pydantic.dev/latest/concepts/pydantic_settings/
- GitHub:https://github.com/pydantic/pydantic-settings
- Pydantic 文档:https://docs.pydantic.dev/
- FastAPI 配置:https://fastapi.tiangolo.com/advanced/settings/