PAYATHON 2026

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,并不意味着测试一定直接使用这个日常开发数据库文件。

备注:内容仅供参考。