Python配置管理利器:configurations库实现多环境配置自动化
1. 项目概述:一个配置管理的“瑞士军刀”
如果你和我一样,在多个项目间反复横跳,或者负责一个需要部署到不同环境(开发、测试、生产)的复杂系统,那么“配置管理”这四个字,大概率是你日常开发中的痛点之一。配置文件散落在各处,不同环境需要手动修改,一不小心就把测试环境的数据库地址提交到了生产代码库,这种“事故”相信不少人都经历过。今天要聊的这个开源项目ilyachenko/configurations,就是一位名叫 Ilya Chenkov 的开发者,为了解决这个普遍痛点而打造的一个 Python 配置管理工具。它不是什么颠覆性的框架,但在我看来,它是一把非常趁手的“瑞士军刀”,核心目标就一个:让不同环境下的配置加载变得清晰、安全、自动化。
简单来说,configurations库让你能够根据一个环境变量(比如DJANGO_SETTINGS_MODULE或自定义的ENVIRONMENT),自动加载对应环境的配置模块。它最初是为了无缝集成 Django 框架而设计的,但其设计理念和实现方式,使其完全可以应用于任何 Python 项目。想象一下,你的项目里有一个settings目录,里面放着development.py、testing.py、production.py,你只需要在启动应用前设置ENVIRONMENT=production,代码就能自动读取production.py里的所有配置项,而无需在代码中写任何if-else来判断环境。这不仅仅是代码整洁的问题,更是安全性和部署可靠性的保障。
这个项目特别适合哪些人呢?首先是 Django 开发者,它能完美替代 Django 原生的多settings.py方案,提供更优雅的隔离。其次是任何需要处理多环境配置的 Python 后端开发者,无论是 Flask、FastAPI 还是自研框架。最后,对于那些崇尚“十二要素应用”(12-Factor App)方法论,特别是其中“配置”原则的 DevOps 工程师和架构师来说,这个库提供了一种轻量级且符合最佳实践的实现路径。接下来,我们就深入这把“瑞士军刀”的内部,看看它到底是如何工作的,以及如何在实战中用好它。
2. 核心设计理念与工作原理拆解
2.1 为什么需要专门的配置管理库?
在深入configurations之前,我们先明确一下“配置”到底是什么。在软件工程中,配置通常指那些在部署时可能发生变化,但不应该被硬编码在源代码中的设置。典型的配置包括:数据库连接字符串、第三方服务的 API 密钥、日志级别、功能开关等。处理这些配置,常见的“野路子”包括:
- 硬编码在代码里:最糟糕的做法,不同环境需要改代码,极易出错且不安全。
- 使用多个配置文件,用
if-else切换:比如在settings.py开头判断os.environ.get('ENV')。这比硬编码好,但逻辑散落,配置文件本身仍然可能包含敏感信息。 - 使用
.env文件:通过python-dotenv等库加载环境变量。这是很大的进步,将配置与代码分离。但当配置项非常多,且不同环境差异很大时,一个.env文件可能不够,或者需要维护多个.env文件,管理起来依然麻烦。
configurations库的核心理念,是“基于环境的模块化配置”。它将每个环境的配置视为一个独立的 Python 模块。这样做的好处非常明显:
- 隔离性:开发、测试、生产的配置完全物理隔离,存放在不同的文件中,从根源上杜绝了误操作。
- 清晰性:项目结构一目了然,
settings/development.py里就是开发环境的全部配置,新人上手也能快速理解。 - 可继承性:可以定义一个
base.py存放所有环境的通用配置(如项目路径、中间件列表),然后让development.py、production.py去继承并覆盖特定项。这符合 DRY(Don‘t Repeat Yourself)原则。 - 与部署工具天然集成:在 Docker、Kubernetes 或任何 CI/CD 流程中,设置环境变量是标准操作。
configurations利用这一点作为配置切换的触发器,与现代化部署流程完美契合。
2.2 核心机制:Settings类与元类魔法
configurations的工作原理,核心在于一个名为Settings的基类以及 Python 的元类(Metaclass)机制。对于不熟悉元类的读者,你可以把它理解为“类的类”,它能在类被创建时拦截并修改类的定义过程。configurations正是利用这一点,实现了配置的自动加载和验证。
当你创建一个继承自configurations.Settings的类,并设置__module__属性指向你的配置模块(如myproject.settings.development)时,魔法就发生了。Settings的元类会:
- 定位模块:根据
__module__找到对应的 Python 文件。 - 读取变量:遍历该模块中所有大写字母开头的全局变量(这是约定,用于区分配置项和普通变量)。
- 注入类属性:将这些大写变量(如
DEBUG = True,DATABASES = {...})动态地设置为这个Settings类的属性。 - 执行准备:运行该模块中可能存在的
setup()函数(如果定义了的话),用于执行一些环境相关的初始化代码。
最终,你得到一个加载了所有配置项的Settings类实例。在 Django 项目中,你只需要在manage.py和wsgi.py中,将这个实例赋值给os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourproject.settings')所指向的模块路径即可。configurations提供了一个configuration装饰器,可以更优雅地完成这个“包装”过程。
注意:这里有一个关键细节。
configurations默认只读取模块中大写的变量。这是为了遵循 Django 配置的惯例,同时也有效避免了将模块中的辅助函数、导入的类等误当作配置项加载。如果你的配置项需要使用小写(虽然不推荐),你需要通过重写元类或使用其他钩子函数来自定义这一行为。
2.3 与 Django 的深度集成模式
由于出身于 Django 生态,configurations与 Django 的集成是最丝滑的。它不仅仅是一个配置加载器,还针对 Django 的常见需求做了特别优化:
- 自动处理
django.conf.settings:当你使用@configuration装饰器后,configurations会确保django.conf.settings对象指向的是正确环境加载后的配置。这意味着你项目中任何地方通过from django.conf import settings获取到的,都是当前环境下的配置,无需任何修改。 - 内置的配置 Mixin:
configurations提供了一系列预定义的 Mixin 类,用于快速启用某些功能。例如:WebpackMixin:帮你自动配置STATICFILES_DIRS以集成 Webpack 开发服务器。DatabaseURLMixin:允许你使用一个DATABASE_URL环境变量(如postgres://user:pass@host:port/dbname)来配置数据库,而不是手写复杂的DATABASES字典。这非常符合 Heroku 等云平台的做法。EmailURLMixin:类似地,使用EMAIL_URL环境变量配置邮件后端。
- 环境变量优先级:
configurations遵循一个重要的原则:环境变量的优先级高于配置文件。这意味着,即使在production.py里写死了SECRET_KEY = 'in-file-key',如果你在系统环境变量中设置了SECRET_KEY=env-key,那么最终生效的会是env-key。这为安全地管理密钥(通过 Docker Secrets、K8s Secrets 或云服务商的环境变量管理)提供了便利,你可以在配置文件中放置一个默认值或占位符,而将真正的生产密钥通过更安全的方式注入。
这种设计使得configurations不仅管理了配置的“结构”和“来源”,还很好地融入了 Django 的工作流和安全最佳实践。
3. 从零开始:项目配置实战指南
3.1 基础项目结构与环境设置
让我们从一个干净的 Django 项目开始,实战演练如何集成configurations。假设项目名为myapp。
首先,通过 pip 安装:
pip install configurations接下来,重构你的项目目录结构。传统的 Django 项目可能只有一个settings.py文件。我们需要将其改造成一个配置包(package)。
myapp/ ├── manage.py ├── myapp/ │ ├── __init__.py │ ├── urls.py │ ├── wsgi.py │ └── settings/ # 将原来的 settings.py 替换为 settings 目录 │ ├── __init__.py │ ├── base.py # 通用基础配置 │ ├── development.py # 开发环境配置 │ ├── testing.py # 测试环境配置 │ └── production.py # 生产环境配置 └── requirements.txt关键文件内容解析:
myapp/settings/__init__.py这个文件是配置包的入口。它的核心作用是定义一个Settings类,并根据环境变量决定加载哪个子模块。内容通常如下:import os from configurations import Settings class Settings(Settings): # 设置配置根目录,用于构建其他路径(如模板、静态文件) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 通过环境变量 `ENVIRONMENT` 决定加载哪个配置,默认为 `development` ENVIRONMENT = os.environ.get('ENVIRONMENT', 'development').lower() # 根据 ENVIRONMENT 动态设置 __module__ # 这行代码是魔法生效的关键 __module__ = f"myapp.settings.{ENVIRONMENT}" # 你可以在这里定义一些所有环境都绝对通用的、无需覆盖的变量 # 但更推荐的做法是放在 `base.py` 中myapp/settings/base.py这里是所有配置的基石,包含所有环境共享的设置。import os from pathlib import Path # 从上一级目录的 __init__.py 中导入 BASE_DIR 可能更准确 # 这里我们直接从环境变量或计算获取 BASE_DIR = Path(__file__).resolve().parent.parent.parent SECRET_KEY = os.environ.get('SECRET_KEY', 'your-default-insecure-secret-key-for-dev-only') DEBUG = False # 在 base 中默认为 False,在各子环境中覆盖 ALLOWED_HOSTS = [] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 你的自定义应用 'myapp.core', ] MIDDLEWARE = [ ... ] ROOT_URLCONF = 'myapp.urls' TEMPLATES = [ ... ] WSGI_APPLICATION = 'myapp.wsgi.application' # 数据库 - 在 base 中定义一个默认的 SQLite,被子环境覆盖 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } AUTH_PASSWORD_VALIDATORS = [ ... ] LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_TZ = True STATIC_URL = 'static/' STATIC_ROOT = BASE_DIR / 'staticfiles' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'myapp/settings/development.py开发环境配置,从base继承并覆盖特定项。from .base import * # 导入所有基础配置 DEBUG = True ALLOWED_HOSTS = ['localhost', '127.0.0.1'] # 开发环境使用更详细的日志 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'root': { 'handlers': ['console'], 'level': 'DEBUG', }, } # 可以使用环境变量,但在此文件中提供默认值 DATABASES['default']['NAME'] = BASE_DIR / 'db_dev.sqlite3' # 开发时可能需要 Django Debug Toolbar 等工具 INSTALLED_APPS += ['debug_toolbar'] MIDDLEWARE.insert(0, 'debug_toolbar.middleware.DebugToolbarMiddleware') INTERNAL_IPS = ['127.0.0.1']myapp/settings/production.py生产环境配置,安全性和性能是首要考虑。from .base import * DEBUG = False # 必须设置正确的主机名 ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',') # SECRET_KEY 必须从环境变量读取,base中的默认值不安全 SECRET_KEY = os.environ['SECRET_KEY'] # 生产环境必须设置此变量,否则会抛出 KeyError # 数据库 - 使用环境变量 DATABASE_URL import dj_database_url DATABASES = { 'default': dj_database_url.config( conn_max_age=600, conn_health_checks=True, ) } # 静态文件服务(假设使用 WhiteNoise) STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') # 生产环境日志配置(输出到文件或外部服务) LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'WARNING', 'class': 'logging.handlers.RotatingFileHandler', 'filename': BASE_DIR / 'logs' / 'django.log', 'maxBytes': 1024 * 1024 * 5, # 5 MB 'backupCount': 5, }, }, 'root': { 'handlers': ['file'], 'level': 'WARNING', }, }
3.2 关键文件改造:manage.py 与 wsgi.py
要让 Django 识别我们的新配置结构,需要修改入口文件。
manage.py的修改:
#!/usr/bin/env python import os import sys def main(): """Run administrative tasks.""" # 关键修改:在导入 django 之前设置环境变量 os.environ.setdefault('ENVIRONMENT', 'development') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed?" ) from exc execute_from_command_line(sys.argv) if __name__ == '__main__': main()这里我们设置了默认的ENVIRONMENT为development。当你运行python manage.py runserver时,就会自动加载development.py的配置。
myapp/wsgi.py的修改(用于生产部署,如 Gunicorn):
import os from configurations.wsgi import get_wsgi_application # 生产服务器(如Gunicorn)会在启动时设置 ENVIRONMENT 变量(例如 ENVIRONMENT=production) # 所以这里不需要设置默认值,直接读取即可。 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings') application = get_wsgi_application()注意,这里从configurations.wsgi导入了get_wsgi_application,而不是 Django 原生的。这个函数内部会处理配置的加载。
myapp/asgi.py(如果使用 ASGI,如 Daphne)的类似修改:
import os from configurations.asgi import get_asgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings') application = get_asgi_application()3.3 使用 Mixin 提升效率
configurations的 Mixin 功能可以极大减少样板代码。例如,使用DatabaseURLMixin:
首先,安装依赖:pip install dj-database-url。
然后,修改myapp/settings/__init__.py:
import os from configurations import Configuration from configurations.importer import install # 安装配置导入钩子,确保 django.conf.settings 正常工作 install() class Dev(Configuration): # 使用 DatabaseURLMixin from configurations.mixins import DatabaseURLMixin class Mixins(DatabaseURLMixin): pass # 环境变量 DATABASE_URL 将自动被解析并覆盖 DATABASES 设置 # 例如:export DATABASE_URL=postgres://user:password@localhost:5432/mydb DEBUG = True class Prod(DatabaseURLMixin, Configuration): DEBUG = False # ... 其他生产配置 # 根据环境变量选择配置类 ENVIRONMENT = os.environ.get('ENVIRONMENT', 'dev').lower() if ENVIRONMENT == 'prod': settings = Prod else: settings = Dev然后在base.py中,就不再需要定义DATABASES了,它会被 Mixin 自动处理。这种方式让配置更加声明式和简洁。
实操心得:虽然 Mixin 很方便,但我建议在项目初期或配置项较少时,先使用显式的继承方式(
from .base import *)。这能让配置的流向更加清晰可见。当项目成熟,某些配置模式(如数据库、邮件、缓存都通过 URL 配置)固定下来后,再引入 Mixin 进行抽象,可以更好地管理复杂度。
4. 高级用法与最佳实践
4.1 环境变量的精细化管理
configurations推崇环境变量,但如何管理大量环境变量是个问题。我推荐以下实践:
使用
.env文件进行本地开发:在项目根目录创建.env.development,.env.testing等文件,使用python-dotenv在配置模块加载前读取。但要注意,不要将.env文件提交到版本库(务必加入.gitignore)。可以在项目中提供一个.env.example文件,列出所有需要的环境变量及其说明。myapp/settings/development.py顶部可以添加:from dotenv import load_dotenv load_dotenv('.env.development') # 从指定文件加载 # 或者 load_dotenv() 默认加载 .env分层与默认值策略:
- 敏感信息(SECRET_KEY, API Keys):绝不在配置文件中写死,甚至不提供默认值。强制要求从环境变量读取,并在生产环境部署文档中明确说明。在开发环境,通过
.env文件提供。 - 环境特定配置(ALLOWED_HOSTS, DATABASE_URL):在环境配置文件中(如
production.py)提供从环境变量读取的逻辑,并给出清晰的错误提示。 - 通用配置(INSTALLED_APPS, MIDDLEWARE):直接在
base.py或环境配置文件中定义。
- 敏感信息(SECRET_KEY, API Keys):绝不在配置文件中写死,甚至不提供默认值。强制要求从环境变量读取,并在生产环境部署文档中明确说明。在开发环境,通过
类型转换:环境变量都是字符串,但配置可能需要布尔值、整数、列表等。
configurations本身不处理类型转换。常见的做法是使用辅助函数:def get_bool_env(key, default=False): val = os.environ.get(key, '') if val.lower() in ('true', '1', 'yes', 'on'): return True elif val.lower() in ('false', '0', 'no', 'off'): return False else: return default DEBUG = get_bool_env('DEBUG', False)或者,对于列表(如
ALLOWED_HOSTS):ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',') ALLOWED_HOSTS = [h.strip() for h in ALLOWED_HOSTS if h.strip()]
4.2 测试环境的特殊处理
测试环境(如运行pytest或python manage.py test)的配置通常需要一些特殊设置,例如使用内存数据库、关闭密码哈希器的慢速算法以加速测试、配置测试运行器等。
你可以创建一个myapp/settings/testing.py:
from .base import * # 测试环境通常也需要 DEBUG=False 来模拟生产行为 DEBUG = False # 使用内存中的 SQLite 数据库,测试速度最快,且完全隔离 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', } } # 使用更快的密码哈希器 PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.MD5PasswordHasher', ] # 禁用某些中间件(如 CSRF、Session)以简化测试 MIDDLEWARE = [ m for m in MIDDLEWARE if not any( exclude in m for exclude in [ 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', ] ) ] # 设置测试运行器(如果使用 pytest-django,这个可能不需要) TEST_RUNNER = 'django.test.runner.DiscoverRunner'然后,在运行测试时,设置ENVIRONMENT=testing。在pytest.ini或setup.cfg中,你可以通过addopts或在 conftest.py 中使用os.environ.setdefault('ENVIRONMENT', 'testing')来确保测试使用正确的配置。
4.3 配置验证与预加载检查
错误的配置可能导致应用在运行时才崩溃。configurations提供了一个setup()钩子,可以在配置加载后、Django 应用启动前执行一些验证逻辑。
在任意配置模块(如production.py)中定义:
def setup(): """ 配置加载后执行的函数。 用于验证环境变量、检查依赖服务等。 """ import sys from django.core.exceptions import ImproperlyConfigured # 示例:检查生产环境必须设置的敏感变量 required_env_vars = ['SECRET_KEY', 'DATABASE_URL'] missing = [var for var in required_env_vars if not os.environ.get(var)] if missing: raise ImproperlyConfigured( f"The following required environment variables are missing: {', '.join(missing)}" ) # 示例:检查 Redis 是否可达(如果使用了缓存) # try: # import redis # r = redis.from_url(os.environ.get('REDIS_URL')) # r.ping() # except redis.ConnectionError: # print("Warning: Redis cache is not reachable.", file=sys.stderr)这个setup()函数会在对应环境的配置模块被加载后自动调用,是进行前置条件检查的绝佳位置。
5. 常见陷阱、问题排查与优化建议
5.1 典型问题与解决方案
在实际使用中,你可能会遇到以下几个典型问题:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
运行manage.py命令时报ModuleNotFoundError: No module named 'myapp.settings' | 1.DJANGO_SETTINGS_MODULE环境变量设置错误。2. myapp/settings/__init__.py中的__module__指向了一个不存在的模块(如ENVIRONMENT变量值不对)。3. Python 路径问题,项目根目录不在 sys.path中。 | 1. 检查manage.py中setdefault的值是否正确。2. 在 __init__.py中打印ENVIRONMENT和__module__的值进行调试。3. 确保在项目根目录下执行命令,或正确设置了 PYTHONPATH。 |
配置项没有按预期被覆盖(例如DEBUG在开发环境仍是False) | 1. 环境变量ENVIRONMENT未正确设置,导致加载了错误的配置模块(如默认的development)。2. 在子配置文件中, from .base import *的顺序有误,后续的赋值被前面的代码覆盖了。3. 配置项名称拼写错误(大小写)。 | 1. 使用print(os.environ.get('ENVIRONMENT'))在配置文件中确认。2. 确保 from .base import *是文件的第一行(除了setup()函数)。3. 仔细检查拼写,配置项应全大写。 |
使用@configuration装饰器时,Django 提示“settings already configured” | 在同一个 Python 进程中多次调用了django.setup()或configurations的初始化逻辑。常见于测试脚本或自定义管理命令中。 | 确保配置加载和 Django 初始化只进行一次。可以使用django.setup()的configure参数,或者在测试的setUp方法中妥善处理。更简单的方法是遵循 Django 和configurations的标准模式,避免手动调用这些函数。 |
| 生产环境静态文件 404 | production.py中可能配置了whitenoise等中间件,但STATIC_ROOT目录不存在或collectstatic命令未运行。 | 1. 确保STATIC_ROOT路径正确且应用有写入权限。2. 在部署流程中加入 python manage.py collectstatic --noinput命令。3. 检查 Web 服务器(如 Nginx)是否正确地代理了静态文件请求(如果不用 WhiteNoise)。 |
5.2 性能与安全考量
配置加载性能:
configurations在启动时动态导入模块并设置属性,会有一次性的开销。对于需要极速冷启动的应用(如 Serverless 函数),这可能是个考量。但在绝大多数 Web 应用场景中,这个开销微乎其微,且只发生在启动时。不要为了所谓的性能而在代码中动态判断环境,那会牺牲代码的清晰度和安全性。配置缓存:Django 的
settings对象在导入后是惰性且基本是静态的。configurations加载后的配置也是如此,不存在运行时反复读取环境变量的开销。环境变量在进程启动时就被读取并固化到配置对象中。敏感信息泄露:这是配置管理的重中之重。
- 绝对禁止将真实的密钥、密码提交到版本控制系统。
base.py或示例文件中的SECRET_KEY必须使用一个仅用于开发的占位符。 - 使用
.gitignore确保.env*文件不会被提交。 - 生产环境的密钥必须通过宿主机的环境变量、Docker Secrets、Kubernetes Secrets 或云服务商的密钥管理服务(如 AWS Secrets Manager, GCP Secret Manager)来注入。
configurations通过os.environ读取,与这些服务能很好地集成。 - 定期轮换密钥。
- 绝对禁止将真实的密钥、密码提交到版本控制系统。
5.3 进阶:自定义配置加载逻辑
虽然configurations的默认行为适用于大多数场景,但有时你可能需要更复杂的逻辑,比如根据不同的部署区域(REGION)加载不同的配置文件,或者合并多个来源的配置。
你可以通过继承configurations.Configuration类并重写其__init__或pre_setup/post_setup方法来实现。例如,实现一个根据REGION加载额外配置的 Mixin:
from configurations import Configuration import importlib class RegionalMixin: @classmethod def pre_setup(cls): """在主要配置加载前执行""" super().pre_setup() region = os.environ.get('AWS_REGION', 'us-east-1') # 动态导入区域特定配置 try: region_module = importlib.import_module(f'myapp.settings.regions.{region.replace("-", "_")}') # 将区域配置中的大写变量更新到当前类中 for key in dir(region_module): if key.isupper(): setattr(cls, key, getattr(region_module, key)) except ModuleNotFoundError: # 如果该区域没有特定配置,则忽略 pass class ProdConfig(RegionalMixin, Configuration): DEBUG = False # ... 其他基础生产配置这种灵活性确保了configurations能够适应复杂的企业级部署场景。
6. 在非 Django 项目中的运用
configurations的核心价值并不局限于 Django。任何 Python 项目都可以借鉴其模式,甚至直接使用其Configuration基类来管理配置。
假设你有一个 FastAPI 项目,项目结构如下:
my_fastapi_app/ ├── config/ │ ├── __init__.py │ ├── base.py │ ├── development.py │ └── production.py ├── main.py └── requirements.txtconfig/__init__.py可以这样写:
import os from configurations import Configuration class Settings(Configuration): ENVIRONMENT = os.environ.get('ENVIRONMENT', 'development').lower() __module__ = f"config.{ENVIRONMENT}" # 创建一个全局可访问的配置对象 settings = Settings()config/development.py:
from .base import * API_DEBUG = True DATABASE_URL = "sqlite:///./test.db" LOG_LEVEL = "DEBUG"main.py中如何使用:
from fastapi import FastAPI from config import settings app = FastAPI(debug=settings.API_DEBUG) @app.get("/") def read_root(): # 可以直接使用 settings 对象 return {"environment": settings.ENVIRONMENT, "log_level": settings.LOG_LEVEL} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)启动时,通过环境变量切换配置:
ENVIRONMENT=production uvicorn main:app --reload这种方式将配置的加载逻辑与业务代码完全解耦,保持了代码的整洁和可测试性。它证明了configurations所倡导的“基于环境的模块化配置”理念,是一种具有普适性的优秀实践模式。
