Django 在 GitLab CI 中设置 APP_ENV=local 后为何仍使用 PostgreSQL?
结论
如果测试加载了包含这段分支逻辑的 settings,导入时 APP_ENV 为 local,且之后没有覆盖 DATABASES,就应该使用 SQLite。
现有错误只表明运行时曾尝试连接 PostgreSQL,不能据此判断 APP_ENV 没有生效。需要检查测试实际加载的 settings、进程中的环境变量和最终的数据库配置。声明 PostgreSQL services 不会让 Django 自动选择 PostgreSQL。
先查看 Django 实际使用的配置
在测试任务中临时加入以下诊断命令,保留原来的测试命令:
script:
- |
uv run python manage.py shell -c 'import os; from django.conf import settings; print("APP_ENV:", repr(os.getenv("APP_ENV"))); print("DJANGO_SETTINGS_MODULE:", os.getenv("DJANGO_SETTINGS_MODULE")); print("Loaded settings:", settings.SETTINGS_MODULE); print("Database engines:", {alias: config.get("ENGINE") for alias, config in settings.DATABASES.items()})'
- uv run python manage.py test
命令只输出环境选择、settings 模块名和数据库引擎,不输出数据库密码。
根据结果继续排查:
APP_ENV不是精确的'local':检查 GitLab CI 变量、任务继承配置和启动脚本是否设置了其他值。注意变量名、大小写和空格是否一致。- 加载的模块直接指向
production:检查DJANGO_SETTINGS_MODULE、manage.py和命令中的--settings参数。直接加载生产配置时,包中的条件导入未必能决定最终使用的DATABASES。 APP_ENV为'local',但默认引擎仍是 PostgreSQL:检查后续导入或赋值是否覆盖了DATABASES。- 诊断显示 SQLite,测试仍连接 PostgreSQL:检查测试代码是否修改 settings、是否使用其他数据库别名,以及是否存在直接调用 PostgreSQL 驱动的代码。结合完整 traceback 定位连接发起的位置。
这些输出反映的是诊断命令启动时的配置。如果测试代码随后修改了配置,还需要检查对应的测试路径。
检查 settings 入口和导入顺序
原始材料中的文件名写作 settings/_ init _.py。如果实际文件也这样命名,需要改为 Python 包初始化文件的标准名称 settings/__init__.py;如果只是粘贴时的格式问题,无需修改文件名。
分支代码必须正确缩进:
import os
APP_ENV = os.getenv("APP_ENV", "local")
if APP_ENV == "local":
from .local import DATABASES
elif APP_ENV == "production":
from .production import DATABASES
else:
raise ValueError("Incorrect configuration")
原样粘贴的无缩进代码会产生语法错误,不能把材料中的排版直接当作实际运行代码。
还要检查入口文件后面是否导入了其他配置,例如生产配置,或者重新赋值了 DATABASES = ...。后执行的赋值可能覆盖前面选中的 SQLite 配置。如果项目需要先加载 base 中的公共设置,应在可能覆盖数据库配置的公共设置导入之后,再进行最终的数据库选择。
同时确认 DJANGO_SETTINGS_MODULE 指向预期入口。假设项目的配置包名是 config,且环境分支位于 config/settings/__init__.py,对应模块应为:
config.settings
config 只是示例,需要替换为实际 Python 包名。
调整使用 SQLite 的 CI 任务
确认 settings 入口正确后,可以将相关任务配置整理为:
backend:test:
stage: test
image: python:3.13-slim
variables:
APP_ENV: "local"
script:
- APP_ENV=local uv run python manage.py test
命令前的 APP_ENV=local 为该命令显式设置环境变量,便于排除启动命令前变量值不符合预期的情况。如果应用随后改写了环境变量或覆盖了 DATABASES,仍需要修正相应代码。
这里展示的是与数据库选择有关的任务配置,项目原有的 uv 安装和依赖准备步骤仍需保留。如果测试完全使用 SQLite,且其他步骤也不依赖 PostgreSQL,可以删除该任务的 PostgreSQL service。
如果希望测试固定使用某个独立 settings 模块,也可以显式指定:
uv run python manage.py test --settings=config.settings.local
这要求 config.settings.local 本身是一份可供 Django 使用的完整配置,包含公共设置和数据库设置。题目中的 local.py 只展示了导入 BASE_DIR 和定义 DATABASES,不能据此认定它可以直接作为完整 settings 模块使用。
如何理解 Unix socket 错误
错误中的路径:
/var/run/[MASKED]ql/.s.PGSQL.5432
表明这次 PostgreSQL 连接尝试使用了 Unix socket。这通常与未指定有效的 PostgreSQL HOST 有关,但仅凭这段错误不能确定具体是哪处配置造成的。
如果最终需要使用 PostgreSQL,再检查服务是否可用,并让 POSTGRES_HOST 对应 CI 中的服务地址,例如题目声明的别名 postgres。当前目标是使用 SQLite,应先让最终数据库引擎变为 django.db.backends.sqlite3;仅修复 PostgreSQL 地址不能解决数据库选错的问题。
Django 的标准测试运行器会根据选定的数据库后端创建测试数据库。local.py 中配置了 db.sqlite3,并不意味着测试一定直接使用这个日常开发数据库文件。
备注:内容仅供参考。
