Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pydantic nested setting objects load env variables from file

Using pydantic setting management, how can I load env variables on nested setting objects on a main settings class? In the code below, the sub_field env variable field doesn't get loaded. field_one and field_two load fine. How can I load an environment file so the values are propagated down to the nested sub_settings object?

from typing import Optional
from pydantic import BaseSettings, Field


class SubSettings(BaseSettings):
    sub_field: Optional[str] = Field(None, env='SUB_FIELD')


class Settings(BaseSettings):
    field_one: Optional[str] = Field(None, env='FIELD_ONE')
    field_two: Optional[int] = Field(None, env='FIELD_TWO')
    sub_settings: SubSettings = SubSettings()


settings = Settings(_env_file='local.env')
like image 333
stormakt Avatar asked Jun 18 '26 09:06

stormakt


1 Answers

There are some examples of nested loading of pydantic env variables in the docs.

Option 1

If you're willing to adjust your variable names, one strategy is to use env_nested_delimiter to denote nested fields. This appears to be the way that pydantic expects nested settings to be loaded, so it should be preferred when possible.

So with a local.env like this:

FIELD_ONE=one
FIELD_TWO=2
SUB_SETTINGS__SUB_FIELD=value

You should be able to load the settings in this way

from typing import Optional
from pydantic import BaseModel, BaseSettings


class SubSettings(BaseModel):
     # ^ Note that this inherits from BaseModel, not BaseSettings
    sub_field: Optional[str]


class Settings(BaseSettings):
    field_one: Optional[str]
    field_two: Optional[int]
    sub_settings: SubSettings

    class Config:
        env_nested_delimiter = '__'

Alternate

If you don't want to use the env_nested_delimiter functionality, you could load both sets of settings from the same local.env file. Then pass the loaded SubSettings to Settings directly. This can be done by overriding the Settings class __init__ method

With this local.env

FIELD_ONE=one
FIELD_TWO=2
SUB_FIELD=value

use the following to load the settings

from typing import Optional
from pydantic import BaseModel, BaseSettings, Field

class SubSettings(BaseSettings):
    sub_field: Optional[str]

class Settings(BaseSettings):
    field_one: Optional[str]
    field_two: Optional[int]
    sub_settings: SubSettings

    def __init__(self, *args, **kwargs):
        kwargs['sub_settings'] = SubSettings(_env_file=kwargs['_env_file'])
        super().__init__(*args, **kwargs)


settings = Settings(_env_file='local.env')
like image 134
cstoltze Avatar answered Jun 19 '26 23:06

cstoltze



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!