ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FastAPI 配置管理实战:用 Pydantic Settings 从环境变量与 .env 文件加载设置

FastAPI 配置管理实战:用 Pydantic Settings 从环境变量与 .env 文件加载设置 FastAPI 配置管理实战用 Pydantic Settings 从环境变量与 .env 文件加载设置【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本篇指南讲解 FastAPI 官方文档《Einstellungen und Umgebungsvariablen设置与环境变量》一节的核心内容如何把应用的外部配置密钥、数据库地址、管理员邮箱等从环境变量读取进来并用 Pydantic 的BaseSettings完成类型转换与校验进一步演示将Settings放入独立模块、以依赖注入方式提供、从.env文件加载以及用lru_cache避免每次请求重复读盘的完整实践方案。读完你将掌握一套可直接复制到生产项目的配置管理模式并能通过依赖覆盖轻松完成测试。为什么用环境变量管理应用配置在许多场景下你的应用需要一些外部设置或配置例如机密密钥secrets数据库连接凭证、数据库 URL邮件服务的账号信息等。这些配置大多可变例如数据库 URL 在开发、测试、生产环境中各不相同而且其中很多属于敏感信息。因此业界通用做法是不把它们写死在代码里而是以**环境变量Environment Variable简称 Env-Var**的形式提供由应用启动时读取。环境变量是存在于 Python 代码之外、由操作系统以及该机器上的其他程序持有并可被读取的值。你可以在执行某个命令时为它临时赋值具体语法因平台而异下文会给出 Linux/macOS/Windows 的命令。由于环境变量只能承载文本字符串它存在于 Python 之外必须与系统及其他程序、跨 Linux/Windows/macOS 等操作系统保持兼容所以从环境变量读出的值在 Python 里永远是str。任何类型转换例如转成int和校验都必须由代码自己完成——这正是引入 Pydantic Settings 的意义所在。安装pydantic-settings幸运的是Pydantic 官方提供了专门处理“来自环境变量的设置”的工具pydantic-settings包其中的BaseSettings会读取环境变量并自动完成转换与校验。向项目添加该包$ uv add pydantic-settings它也已经包含在 FastAPI 的all额外依赖组中安装fastapi[all]即可获得$ uv add fastapi[all]这一点可以从本仓库的 pyproject.toml 中得到印证FastAPI 的多个 extras 依赖组中都声明了pydantic-settings 2.0.0另有一个组声明为2.1.0,3.0.0说明该包是官方文档方案的一等公民。创建并使用Settings对象从pydantic_settings导入BaseSettings然后像定义普通 Pydantic 模型一样定义一个子类声明带类型注解的类属性可写默认值也能用Field()等全部 Pydantic 校验工具各种数据类型、附加校验规则均可用。官方示例代码 tutorial001_py310.py 的完整内容如下from fastapi import FastAPI from pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str Awesome API admin_email: str items_per_user: int 50 settings Settings() app FastAPI() app.get(/info) async def info(): return { app_name: settings.app_name, admin_email: settings.admin_email, items_per_user: settings.items_per_user, }要点解析admin_email没有默认值因此是必填项如果环境里既没有ADMIN_EMAIL变量、也没有.env提供实例化Settings()时会直接抛出校验错误起到“快速失败”的作用items_per_user: int 50声明为int环境变量里的字符串50会被自动转换成整数app_name: str Awesome API有默认值未提供环境变量时使用默认值。当你实例化这个类如settings Settings()时Pydantic 会忽略大小写地读取环境变量大写变量APP_NAME会被映射到属性app_name。数据随后被转换和校验于是你在代码中使用的就是带正确类型的值例如items_per_user保证是int。提示如果你想要一份可直接复制粘贴的完整示例建议直接使用本文最后给出的app03版本依赖 .envlru_cache的完整形态而不是上面这个最简版。运行服务器以环境变量传入配置写好代码后启动服务器时把配置作为环境变量传入即可。例如设置ADMIN_EMAIL和APP_NAMELinux / macOS / Windows Bash$ ADMIN_EMAILdeadpoolexample.com APP_NAMEChimichangApp uv run fastapi run main.py INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRLC to quit)Windows PowerShell$ $Env:ADMIN_EMAIL deadpoolexample.com $ $Env:APP_NAME ChimichangApp $ uv run fastapi run main.py INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRLC to quit)提示在 Bash 中要为单个命令设置多个环境变量用空格把它们分隔开并全部放在命令之前。运行后访问/info你会得到admin_email为deadpoolexample.com来自环境变量app_name为ChimichangApp来自环境变量items_per_user保持默认值50未提供环境变量。将设置放入独立模块按照 FastAPI 更大规模应用多文件组织的惯例可以把设置放到单独的模块里例如 更大的应用教程 所述。新建文件config.py对应 app01_py310/config.pyfrom pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str Awesome API admin_email: str items_per_user: int 50 settings Settings()然后在main.py对应 app01_py310/main.py中导入并使用from fastapi import FastAPI from .config import settings app FastAPI() app.get(/info) async def info(): return { app_name: settings.app_name, admin_email: settings.admin_email, items_per_user: settings.items_per_user, }提示模块目录下还需要一个__init__.py文件见 app01_py310/init.py这一点在“更大的应用——多文件”一节中已说明。这种方式简单直接但settings是一个全局对象测试时难以替换为不同配置。下面给出更灵活的方案。用依赖注入提供Settings有些场景下与其使用一个到处引用的全局settings对象不如把设置作为依赖提供。这在测试时特别有用覆盖一个依赖比替换全局对象容易得多。配置文件基于上一节的config.py改动是不再创建默认实例settings Settings()对应 app02_an_py310/config.pyfrom pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str Awesome API admin_email: str items_per_user: int 50主应用文件在main.py对应 app02_an_py310/main.py中创建一个依赖函数它返回一个新的config.Settings()实例from functools import lru_cache from typing import Annotated from fastapi import Depends, FastAPI from .config import Settings app FastAPI() lru_cache def get_settings(): return Settings() app.get(/info) async def info(settings: Annotated[Settings, Depends(get_settings)]): return { app_name: settings.app_name, admin_email: settings.admin_email, items_per_user: settings.items_per_user, }提示lru_cache的作用在下面专门展开讲。阅读时可以先把它当作普通函数看待。然后在路径操作函数中以Depends(get_settings)的方式声明依赖需要配置的地方就能拿到settings。设置与测试测试时只需为get_settings创建一个依赖覆盖dependency override即可提供另一份设置对象。官方示例 app02_an_py310/test_main.pyfrom fastapi.testclient import TestClient from .config import Settings from .main import app, get_settings client TestClient(app) def get_settings_override(): return Settings(admin_emailtesting_adminexample.com) app.dependency_overrides[get_settings] get_settings_override def test_app(): response client.get(/info) data response.json() assert data { app_name: Awesome API, admin_email: testing_adminexample.com, items_per_user: 50, }在覆盖函数里我们创建Settings时显式传入一个新的admin_email值并返回该对象随后测试/info端点确认返回的就是被覆盖后的值。这个方案在本仓库的测试套件中有真实验证test_app02.py 会对app02_py310与app02_an_py310两种写法分别运行依赖覆盖场景确认覆盖后的admin_email生效。读取.env文件当设置项很多、且在多套环境间经常变化时可以把它们写进一个文件再从中读取方式与读取环境变量一致。这一做法已非常普遍拥有专门的名字把这类环境变量放在一个.env文件中该文件通称dotenv 文件。提示在 Linux、macOS 等类 Unix 系统上以点.开头的文件是隐藏文件。dotenv 文件也不必恰好叫.env这个名字只是惯例。Pydantic 支持通过外部库读取这类文件需要为项目添加python-dotenvuv add python-dotenv。.env文件内容示例ADMIN_EMAILdeadpoolexample.com APP_NAMEChimichangApp从.env读取设置更新config.py对应 app03_an_py310/config.py为Settings类增加model_configfrom pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): app_name: str Awesome API admin_email: str items_per_user: int 50 model_config SettingsConfigDict(env_file.env)提示model_config属性仅用于 Pydantic 自身的配置说明与你的业务字段无关。这里通过SettingsConfigDict(env_file.env)告诉 Pydantic 从哪个 dotenv 文件读取。注意 Pydantic Settings 的读取优先级真实环境变量的值会覆盖.env文件中的同名变量所以本地调试时仍可用命令行临时覆盖。对应的main.pyapp03_an_py310/main.py与app02版本基本相同只是改从config模块取类from functools import lru_cache from typing import Annotated from fastapi import Depends, FastAPI from . import config app FastAPI() lru_cache def get_settings(): return config.Settings() app.get(/info) async def info(settings: Annotated[config.Settings, Depends(get_settings)]): return { app_name: settings.app_name, admin_email: settings.admin_email, items_per_user: settings.items_per_user, }仓库测试 test_app03.py 验证了该场景用monkeypatch.setenv(ADMIN_EMAIL, adminexample.com)注入环境变量后断言get_settings()读到的admin_email adminexample.com且/info端点返回app_name Awesome API、items_per_user 50未注入的字段回落到默认值。用lru_cache只创建一次Settings从磁盘读取文件通常是一个“昂贵”较慢的操作因此通常只想读一次之后复用同一个设置对象而不是每个请求都重新读一遍。但每执行一次Settings()都会创建一个新对象创建时都会重新解析一次.env。如果依赖函数写成def get_settings(): return Settings()那么每个请求都会新建一个对象、重新读一次文件——在生产流量下这是不必要的开销。而使用了lru_cache装饰器后如上面main.py所示Settings对象只在第一次调用时创建✔️ 之后所有对get_settings()的调用后续请求的依赖解析都会直接返回第一次创建并返回的那个对象而不再重新执行函数体、不创建新实例。lru_cache技术细节lru_cache会改造它所装饰的函数对于相同的参数组合直接返回第一次的返回值而不是每次都重新执行函数代码。换言之函数体对每种参数组合只真正执行一次之后该组合的返回值被反复复用。例如lru_cache def say_hi(name: str, salutation: str Ms.): return fHello {salutation} {name}可以观察到如下调用序列的行为say_hi(nameCamila)—— 首次调用真正执行函数代码返回结果say_hi(nameCamila)—— 相同参数直接返回缓存结果不执行函数体say_hi(nameRick)—— 新的参数组合执行函数代码say_hi(nameRick, salutationMr.)—— 又一个新组合执行函数代码say_hi(nameRick)—— 命中第 3 步的缓存say_hi(nameCamila)—— 命中第 1 步的缓存。对于get_settings()函数不接受任何参数因此它永远只会真正执行一次返回同一个值。这样它在效果上几乎等同于一个全局变量但由于它走的是依赖函数你在测试时仍可以轻松地用依赖覆盖替换它——两全其美。lru_cache来自 Python 标准库的functools模块无需安装任何第三方包。小结借助 Pydantic Settingspydantic-settings包你可以用完整的 Pydantic 模型能力类型注解、默认值、Field()校验来管理应用配置核心收益包括用依赖提供设置把Settings通过Depends(get_settings)注入测试时用app.dependency_overrides一行代码即可整体替换配置无需修改任何业务代码支持.env文件通过model_config SettingsConfigDict(env_file.env)从 dotenv 文件加载配置真实环境变量仍可覆盖文件值lru_cache避免重复读盘确保Settings及.env文件的解析只在进程生命周期内执行一次同时因为走依赖注入测试覆盖依然简单。这套模式config.py定义Settingsmain.py定义lru_cache的get_settings 测试中覆盖依赖在本仓库中均有可运行的完整实现与自动化测试示例代码见 docs_src/settings/ 下的tutorial001_py310、app01_py310、app02_an_py310、app03_an_py310各目录对应测试见 tests/test_tutorial/test_settings/ 下的test_tutorial001.py、test_app01.py、test_app02.py、test_app03.py可直接作为落地参考。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表