使用环境变量覆盖 pydantic 模型中的值

问题描述 投票:0回答:1

我正在为 Python 3 应用程序构建一些配置逻辑,并尝试使用

pydantic
pydantic-settings
来管理验证等。我可以从 YAML 文件加载原始设置并从中创建我的设置对象。我还可以从环境变量中读取值。但我不知道如何使环境变量值优先于原始设置:

import os
import yaml as pyyaml
from pydantic_settings import BaseSettings, SettingsConfigDict


class FooSettings(BaseSettings):
    foo: int
    bar: str
    model_config = SettingsConfigDict(env_prefix='FOOCFG__')


raw_yaml = """
foo: 13
bar: baz
"""

os.environ.setdefault("FOOCFG__FOO", "42")

raw_settings = pyyaml.safe_load(raw_yaml)
settings = FooSettings(**raw_settings)

assert settings.foo == 42

如果我在输入 yaml 中注释掉

foo: 13
,断言就会通过。如何使 env 值优先?

python pydantic pydantic-settings
1个回答
0
投票

您确定要环境优先吗?虽然不是普遍存在,但环境变量具有最低优先级是很常见的(通常,顺序是内置默认值,然后是环境变量,然后是配置文件,然后是命令行选项)。偏离这个约定可能会令人惊讶。

您可以通过添加一个字段验证器来获得特定字段所需的行为,该验证器检查适当的环境变量,并优先使用该值而不是现有值(如果可用)。比如:

import os
import yaml as pyyaml
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import field_validator


class FooSettings(BaseSettings):
    model_config = SettingsConfigDict(env_prefix="FOOCFG__")

    foo: int
    bar: str

    @field_validator("foo", mode="after")
    @classmethod
    def validate_foo(cls, val):
        '''Always use the value from the environment if it's available.'''
        if env_val := os.environ.get(f"{cls.model_config['env_prefix']}FOO"):
            return int(env_val)

        return val


raw_yaml = """
foo: 13
bar: baz
"""

os.environ.setdefault("FOOCFG__FOO", "42")

raw_settings = pyyaml.safe_load(raw_yaml)
settings = FooSettings(**raw_settings)

assert settings.foo == 42

如果您想对所有字段执行此操作,您可以使用模型验证器

© www.soinside.com 2019 - 2024. All rights reserved.