如何让继承的Pydantic Settings同时读取带/无前缀的.env变量?
我搭建了一套可快速切换开发、测试、生产等环境的配置体系,期望BaseConfig中的字段优先加载,再加载对应环境前缀的字段,但运行后报错。
简化代码
from pydantic_settings import BaseSettings, SettingsConfigDict class BaseConfig(BaseSettings): ENV_STATE: str SECRET_KEY: str model_config = SettingsConfigDict( env_file=".env", extra="ignore", ) class DevConfig(BaseConfig): DB_USERNAME: str DB_PASSWORD: str model_config = SettingsConfigDict( env_prefix="DEV_", extra="allow", ) def get_config(env_state: str) -> BaseConfig: configs = {"DEV": DevConfig} return configs[env_state]() config = get_config("DEV") print(config.ENV_STATE) print(config.SECRET_KEY) print(config.ALGORITHM) print(config.DB_USERNAME) print(config.DB_PASSWORD)
.env文件内容
ENV_STATE="DEV" SECRET_KEY = "gj5490ghj4569gj" DEV_DB_USERNAME = "username" DEV_DB_PASSWORD = "pass123"
运行错误信息
pydantic_core._pydantic_core.ValidationError: 2 validation errors for DevConfig
ENV_STATE
Field required [type=missing, input_value={'DB_USERNAME': 'username...DB_PASSWORD': 'pass123'}, input_type=dict]
SECRET_KEY
Field required [type=missing, input_value={'DB_USERNAME': 'username...DB_PASSWORD': 'pass123'}, input_type=dict]
可见DevConfig仅加载了带前缀的字段,即便设置了extra="allow"也无效。给BaseConfig中的ENV_STATE和SECRET_KEY设置默认值可正常运行,但无法从.env文件读取这些值,该如何解决?
解决方案
问题核心是子类的model_config直接覆盖了父类配置,导致父类指定的env_file未被继承,同时子类的env_prefix会对所有字段生效(包括父类的ENV_STATE和SECRET_KEY),而这两个字段在.env中没有前缀,因此无法被读取。
方法1:继承并扩展父类的model_config
不要重新定义model_config,而是基于父类配置扩展,保留env_file的同时添加环境前缀:
class DevConfig(BaseConfig): DB_USERNAME: str DB_PASSWORD: str model_config = SettingsConfigDict( **BaseConfig.model_config, env_prefix="DEV_", extra="allow", )
方法2:为父类字段排除环境前缀
在父类字段上添加exclude_from_env_prefix=True,让子类的前缀规则不作用于这些全局字段:
from pydantic_settings import BaseSettings, SettingsConfigDict, Field class BaseConfig(BaseSettings): ENV_STATE: str = Field(exclude_from_env_prefix=True) SECRET_KEY: str = Field(exclude_from_env_prefix=True) model_config = SettingsConfigDict( env_file=".env", extra="ignore", ) class DevConfig(BaseConfig): DB_USERNAME: str DB_PASSWORD: str model_config = SettingsConfigDict( env_prefix="DEV_", extra="allow", )
补充说明
- 方法1更推荐,能完整继承父类配置,避免后续父类配置修改时子类遗漏同步。
- 若需加载未定义的额外字段(如示例中的
ALGORITHM),确保extra="allow"生效,全局字段无需加前缀,环境专属字段添加对应前缀即可。
内容的提问来源于stack exchange,提问作者Nikolaisyl

