我的应用程序有 YAML 配置和环境变量,并且我正在使用 pydantic-settings 将 YAML 和环境变量加载到我的 Pydantic 模型中。 Pydantic 应该更喜欢 env var 而不是 yaml。
但是,我面临嵌套模型的问题,其中环境变量结构与我的嵌套 Pydantic 模型字段不一致。
这是我的 config.yaml:
mongodb:
host: "mongo"
port: 27017
username: "USER"
password: "123456"
name: "db"
collection: "tasks"
s3:
bucket_name: "ai"
我的代码如下所示:
import os
from pydantic_settings import YamlConfigSettingsSource, BaseSettings, PydanticBaseSettingsSource, EnvSettingsSource
from typing import Tuple, Type
from pydantic import BaseModel
class DatabaseSettings(BaseModel):
host: str
port: int
username: str
password: str
name: str
collection: str
class S3Settings(BaseModel):
bucket_name: str
class Settings(BaseSettings):
mongodb: DatabaseSettings
s3: S3Settings
@classmethod
def settings_customise_sources(
cls, settings_cls: Type[BaseSettings], **kwargs
) -> Tuple[PydanticBaseSettingsSource, ...]:
return (
EnvSettingsSource(
settings_cls,
env_nested_delimiter="_",
case_sensitive=False,
env_prefix="PREFIX_"
),
YamlConfigSettingsSource(settings_cls, yaml_file="config.yaml"),
)
db_host = os.environ.get('PREFIX_MONGODB_HOST')
if db_host is not None:
print(f"PREFIX_MONGODB_HOST is set to: {db_host}")
else:
print("PREFIX_MONGODB_HOST is not set")
s3_bucket_name = os.environ.get('PREFIX_S3_BUCKET_NAME')
if s3_bucket_name is not None:
print(f"PREFIX_S3_BUCKET_NAME is set to: {s3_bucket_name}")
else:
print("PREFIX_S3_BUCKET_NAME is not set")
settings = Settings()
print(settings.model_dump())
我定义了以下环境变量:
PREFIX_MONGODB_HOST=本地主机
PREFIX_S3_BUCKET_NAME=某个存储桶
当我运行此代码时,输出是:
```
PREFIX_MONGODB_HOST is set to: localhost
PREFIX_S3_BUCKET_NAME is set to: some-bucket
{'mongodb': {'host': 'localhost', 'port': 27017, 'username': 'USER', 'password': '123456', 'name': 'db', 'collection': 'tasks'}, 's3': {'bucket_name': 'ai'}}
```
问题:
PREFIX_MONGODB_HOST 正确覆盖 YAML 中的 mongodb.host 键。但是,PREFIX_S3_BUCKET_NAME 不会覆盖 s3.bucket_name。问题似乎是 pydantic-settings 将环境变量 PREFIX_S3_BUCKET_NAME 解析为以下 json:
{
"s3": {
"bucket": {
"name": "some-bucket"
}
}
}
这与我的 pydantic 模型不相符。
我希望它将环境变量解析为:
{
"s3": {
"bucket_name": "some-bucket"
}
}
这与 pydantic 模型相对应。 我无法更改环境变量名称 (PREFIX_S3_BUCKET_NAME),因此我正在寻找面向 pydantic-settings 的解决方案来将此环境变量映射到 S3Settings 模型中的 bucket_name 字段。
我尝试过使用别名和不同的配置,但到目前为止没有任何效果。
希望得到任何帮助:)
Pydantic 无法猜测
_
何时是层次结构分隔符以及何时 _
是属性名称的一部分。您需要选择一个明确的层次结构分隔符,例如,__
:
class Settings(BaseSettings):
mongodb: DatabaseSettings
s3: S3Settings
@classmethod
def settings_customise_sources(
cls, settings_cls: Type[BaseSettings], **kwargs
) -> Tuple[PydanticBaseSettingsSource, ...]:
return (
EnvSettingsSource(
settings_cls,
env_nested_delimiter="__",
case_sensitive=False,
env_prefix="PREFIX_",
),
YamlConfigSettingsSource(settings_cls, yaml_file="config.yaml"),
)
然后您可以设置:
PREFIX_MONGODB__HOST=localhost
PREFIX_S3__BUCKET_NAME=some-bucket
你会得到:
{'mongodb': {'host': 'localhost', 'port': 27017, 'username': 'USER', 'password': '123456', 'name': 'db', 'collection': 'tasks'}, 's3': {'bucket_name': 'some-bucket'}}