FastAPI:在相同设置中加载多个环境 class
FastAPI: Loading multiple environments within the same settings class
我一直在努力实现这一目标,但似乎找不到解决方法。我的 FastAPI 项目有以下 main
入口点:
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse
from app.core.config import get_api_settings
from app.api.api import api_router
def get_app() -> FastAPI:
api_settings = get_api_settings()
server = FastAPI(**api_settings.fastapi_kwargs)
server.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
server.include_router(api_router, prefix="/api")
@server.get("/", include_in_schema=False)
def redirect_to_docs() -> RedirectResponse:
return RedirectResponse(api_settings.docs_url)
return server
app = get_app()
到目前为止没有什么特别的。如您所见,我正在导入 get_api_settings
,它包含我的整个服务配置,它看起来像这样:
from functools import lru_cache
from typing import Any, Dict
from pydantic import BaseSettings
class APISettings(BaseSettings):
"""This class enables the configuration of your FastAPI instance
through the use of environment variables.
Any of the instance attributes can be overridden upon instantiation by
either passing the desired value to the initializer, or by setting the
corresponding environment variable.
Attribute `xxx_yyy` corresponds to environment variable `API_XXX_YYY`.
So, for example, to override `api_prefix`, you would set the environment
variable `API_PREFIX`.
Note that assignments to variables are also validated, ensuring that
even if you make runtime-modifications to the config, they should have
the correct types.
"""
# fastapi.applications.FastAPI initializer kwargs
debug: bool = False
docs_url: str = "/docs"
openapi_prefix: str = ""
openapi_url: str = "/openapi.json"
redoc_url: str = "/redoc"
title: str = "Api Backend"
version: str = "0.1.0"
# Custom settings
disable_docs: bool = False
environment: str
@property
def fastapi_kwargs(self) -> Dict[str, Any]:
"""This returns a dictionary of the most commonly used keyword
arguments when initializing a FastAPI instance.
If `self.disable_docs` is True, the various docs-related arguments
are disabled, preventing spec from being published.
"""
fastapi_kwargs: Dict[str, Any] = {
"debug": self.debug,
"docs_url": self.docs_url,
"openapi_prefix": self.openapi_prefix,
"openapi_url": self.openapi_url,
"redoc_url": self.redoc_url,
"title": self.title,
"version": self.version
}
if self.disable_docs:
fastapi_kwargs.update({
"docs_url": None,
"openapi_url": None,
"redoc_url": None
})
return fastapi_kwargs
class Config:
case_sensitive = True
# env_file should be dynamic depending on the
# `environment` env variable
env_file = ""
env_prefix = ""
validate_assignment = True
@lru_cache()
def get_api_settings() -> APISettings:
"""This function returns a cached instance of the APISettings object.
Caching is used to prevent re-reading the environment every time the API
settings are used in an endpoint.
If you want to change an environment variable and reset the cache
(e.g., during testing), this can be done using the `lru_cache` instance
method `get_api_settings.cache_clear()`.
"""
return APISettings()
我正在尝试为多种环境准备此服务:
- 开发
- 阶段
- 产品
对于以上每一个,我有如下三个不同的 .env
文件:
core/configs/dev.env
core/configs/stage.env
core/configs/prod.env
例如,.env
文件如下所示:
environment=dev
frontend_service_url=http://localhost:3000
我无法理解的是如何根据 [=] 中的 environment
属性动态设置 Config
class 中的 env_file = ""
25=] 基本设置 class.
通读 Pydantic's docs 我想我可以使用 customise_sources
class 方法来做这样的事情:
def load_envpath_settings(settings: BaseSettings):
environment = # not sure how to access it here
for env in ("dev", "stage", "prod"):
if environment == env:
return f"app/configs/{environment}.env"
class APISettings(BaseSettings):
# ...
class Config:
case_sensitive = True
# env_file = "app/configs/dev.env"
env_prefix = ""
validate_assignment = True
@classmethod
def customise_sources(cls, init_settings, env_settings, file_secret_settings):
return (
init_settings,
load_envpath_settings,
env_settings,
file_secret_settings,
)
但是我找不到访问 load_envpath_settings
中的 environment
的方法。知道如何解决这个问题吗?或者如果有另一种方法可以做到这一点?我也尝试在我的 APISettings
class 中创建另一个 @property
,它基本上与 load_envpath_settings
相同,但我无法在 Config
class.
首先;通常你会把你想要激活的文件复制到 .env
文件中,然后加载它。但是,如果您想让该 .env
文件控制哪些配置处于活动状态:
您可以有两组配置 - 一组从 .env
加载初始配置(即哪个环境是活动的),另一组从 core/configs/<environment>.env
加载实际的应用程序设置文件。
class AppSettings(BaseSettings):
environment:str = 'development'
这会受到 .env
中给出的配置(默认文件名)的影响。然后,您会将此值用于 load the API configuration by using the _env_file
parameter,所有 BaseSettings
实例都支持该值。
def get_app_settings() -> AppSettings:
return AppSettings()
def get_api_settings() -> APISettings:
app_settings = get_app_settings()
return APISettings(_env_file=f'core/configs/{app_settings.environment}.env') # or os.path.join() and friends
我一直在努力实现这一目标,但似乎找不到解决方法。我的 FastAPI 项目有以下 main
入口点:
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse
from app.core.config import get_api_settings
from app.api.api import api_router
def get_app() -> FastAPI:
api_settings = get_api_settings()
server = FastAPI(**api_settings.fastapi_kwargs)
server.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
server.include_router(api_router, prefix="/api")
@server.get("/", include_in_schema=False)
def redirect_to_docs() -> RedirectResponse:
return RedirectResponse(api_settings.docs_url)
return server
app = get_app()
到目前为止没有什么特别的。如您所见,我正在导入 get_api_settings
,它包含我的整个服务配置,它看起来像这样:
from functools import lru_cache
from typing import Any, Dict
from pydantic import BaseSettings
class APISettings(BaseSettings):
"""This class enables the configuration of your FastAPI instance
through the use of environment variables.
Any of the instance attributes can be overridden upon instantiation by
either passing the desired value to the initializer, or by setting the
corresponding environment variable.
Attribute `xxx_yyy` corresponds to environment variable `API_XXX_YYY`.
So, for example, to override `api_prefix`, you would set the environment
variable `API_PREFIX`.
Note that assignments to variables are also validated, ensuring that
even if you make runtime-modifications to the config, they should have
the correct types.
"""
# fastapi.applications.FastAPI initializer kwargs
debug: bool = False
docs_url: str = "/docs"
openapi_prefix: str = ""
openapi_url: str = "/openapi.json"
redoc_url: str = "/redoc"
title: str = "Api Backend"
version: str = "0.1.0"
# Custom settings
disable_docs: bool = False
environment: str
@property
def fastapi_kwargs(self) -> Dict[str, Any]:
"""This returns a dictionary of the most commonly used keyword
arguments when initializing a FastAPI instance.
If `self.disable_docs` is True, the various docs-related arguments
are disabled, preventing spec from being published.
"""
fastapi_kwargs: Dict[str, Any] = {
"debug": self.debug,
"docs_url": self.docs_url,
"openapi_prefix": self.openapi_prefix,
"openapi_url": self.openapi_url,
"redoc_url": self.redoc_url,
"title": self.title,
"version": self.version
}
if self.disable_docs:
fastapi_kwargs.update({
"docs_url": None,
"openapi_url": None,
"redoc_url": None
})
return fastapi_kwargs
class Config:
case_sensitive = True
# env_file should be dynamic depending on the
# `environment` env variable
env_file = ""
env_prefix = ""
validate_assignment = True
@lru_cache()
def get_api_settings() -> APISettings:
"""This function returns a cached instance of the APISettings object.
Caching is used to prevent re-reading the environment every time the API
settings are used in an endpoint.
If you want to change an environment variable and reset the cache
(e.g., during testing), this can be done using the `lru_cache` instance
method `get_api_settings.cache_clear()`.
"""
return APISettings()
我正在尝试为多种环境准备此服务:
- 开发
- 阶段
- 产品
对于以上每一个,我有如下三个不同的 .env
文件:
core/configs/dev.env
core/configs/stage.env
core/configs/prod.env
例如,.env
文件如下所示:
environment=dev
frontend_service_url=http://localhost:3000
我无法理解的是如何根据 [=] 中的 environment
属性动态设置 Config
class 中的 env_file = ""
25=] 基本设置 class.
通读 Pydantic's docs 我想我可以使用 customise_sources
class 方法来做这样的事情:
def load_envpath_settings(settings: BaseSettings):
environment = # not sure how to access it here
for env in ("dev", "stage", "prod"):
if environment == env:
return f"app/configs/{environment}.env"
class APISettings(BaseSettings):
# ...
class Config:
case_sensitive = True
# env_file = "app/configs/dev.env"
env_prefix = ""
validate_assignment = True
@classmethod
def customise_sources(cls, init_settings, env_settings, file_secret_settings):
return (
init_settings,
load_envpath_settings,
env_settings,
file_secret_settings,
)
但是我找不到访问 load_envpath_settings
中的 environment
的方法。知道如何解决这个问题吗?或者如果有另一种方法可以做到这一点?我也尝试在我的 APISettings
class 中创建另一个 @property
,它基本上与 load_envpath_settings
相同,但我无法在 Config
class.
首先;通常你会把你想要激活的文件复制到 .env
文件中,然后加载它。但是,如果您想让该 .env
文件控制哪些配置处于活动状态:
您可以有两组配置 - 一组从 .env
加载初始配置(即哪个环境是活动的),另一组从 core/configs/<environment>.env
加载实际的应用程序设置文件。
class AppSettings(BaseSettings):
environment:str = 'development'
这会受到 .env
中给出的配置(默认文件名)的影响。然后,您会将此值用于 load the API configuration by using the _env_file
parameter,所有 BaseSettings
实例都支持该值。
def get_app_settings() -> AppSettings:
return AppSettings()
def get_api_settings() -> APISettings:
app_settings = get_app_settings()
return APISettings(_env_file=f'core/configs/{app_settings.environment}.env') # or os.path.join() and friends