You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Django后,Monorepo中Django测试无法被识别的问题

Django升级后GitHub工作流无法找到测试的问题排查

问题背景

我们采用Monorepo存储多个项目,其中包含一个Django项目,基础目录结构如下:

├── README.md
├── code
│   ├── __init__.py
│   ├── gunicorn.conf.py
│   ├── manage.py
│   ├── non-django-project
│   │   ├── ...
│   ├── django_project
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── apps
│   │   │   ├── django_app_1
│   │   │   │   ├── ...
│   │   │   │   ├── tests
│   │   │   │   │   ├── test_something.py
│   │   │   ├── django_app_2
│   │   │   │   ├── ...
│   │   │   │   ├── tests
│   │   │   │   │   ├── test_something.py
│   │   │   ├── django_app_3
│   │   │   │   ├── ...
│   │   │   │   ├── tests
│   │   │   │   │   ├── test_something.py
│   │   │   │   ├── ...
│   │   ├── libs
│   │   │   ├── lib1.py
│   │   │   ├── lib2.py
│   │   │   ├── lib1.py
│   │   │   ├── tests.py

用于运行Django测试的GitHub工作流配置:

name: django
defaults:
  run:
    working-directory: ./code
on:
  workflow_dispatch:
  pull_request:
    paths: ["code/django_project/**", ".github/workflows/django.yml"]
    branches:
      - develop
  push:
    branches:
      - develop    

jobs:
  tests:
    runs-on: ubuntu-20.04
    permissions:
      pull-requests: write
      contents: write
    services:
      redis:
        image: redis
      postgres:
        image: postgres:15.2-alpine
        env:
          POSTGRES_PASSWORD: ****
          POSTGRES_USER: *****
          POSTGRES_DB: ******
        ports:
          - 5432:5432
    env:
      PYTHONUNBUFFERED: 1
    steps:
      - name: checkout
        uses: actions/checkout@v4
      - name: Setup python 3.12
        uses: actions/setup-python@v4
        with:
          python-version: "3.12"
          architecture: x64
          cache: "pip"
          cache-dependency-path: code/django_project/requirements.txt
      - run: sudo apt-get update -qq
      - name: Install & cache APT Packages
        uses: awalsh128/cache-apt-pkgs-action@v1
        with:
          packages: build-essential xvfb gdebi
          version: 1.0
      - name: Install locked pip version
        run: pip install --upgrade pip==23.2.1
      - name: Install python dependencies
        run: pip install -r django_project/requirements.txt
      - name: Run Django tests
        run: coverage run --branch --rcfile=.coveragerc ./manage.py test -v 3 --noinput
      - name: Coverage comment
        uses: py-cov-action/python-coverage-comment-action@v3
        with:
          COVERAGE_PATH: code/
          GITHUB_TOKEN: ${{ github.token }}

settings.py中用于处理路径的代码:

"""settings.py"""
# Build paths inside the project like this: join_to_base_dir(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))


def join_to_base_dir(path):
    return os.path.join(BASE_DIR, path)

import sys
sys.path.append(join_to_base_dir('.'))
sys.path.append(join_to_base_dir('apps'))

报错信息

工作流运行时无法找到测试,报错如下:

Found 1 test(s).
Skipping setup of unused database(s): default.
System check identified no issues (0 silenced).
CODEOWNERS file is not available
code.django_project (unittest.loader._FailedTest.code.django_project) ... ERROR

======================================================================
ERROR: code.django_project (unittest.loader._FailedTest.code.django_project)
----------------------------------------------------------------------
ImportError: Failed to import test module: code.django_project
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/unittest/loader.py", line 415, in _find_test_path
    package = self._get_module_from_name(name)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/unittest/loader.py", line 325, in _get_module_from_name
    __import__(name)
ModuleNotFoundError: No module named 'code.django_project'; 'code' is not a package

该问题在将Django从2.2(Python 3.9)升级到4.2(Python 3.12)后出现,此前运行正常。


问题原因与解决方法

核心原因

Django 4.x的测试加载逻辑比2.x更严格,同时Python 3.12收紧了模块导入规则,之前版本的宽松配置掩盖了路径问题:

  • 工作流在./code目录下运行,Python默认不会将上级目录加入sys.path,导致code无法被识别为Python包
  • 测试命令未明确指定测试目标,Django尝试递归查找测试时错误地尝试导入code.django_project

解决步骤

1. 调整Python路径,将项目根目录加入sys.path

有两种方式可以实现:

  • 方法1:在工作流中设置PYTHONPATH
    修改"Run Django tests"步骤,提前添加上级目录到Python路径:
    export PYTHONPATH="$PYTHONPATH:.." && coverage run --branch --rcfile=.coveragerc ./manage.py test -v 3 --noinput
    
  • 方法2:修改settings.py的路径配置
    更新settings.py中的BASE_DIR和sys.path定义,确保code目录能被识别为包:
    """settings.py"""
    import os
    import sys
    # 修改BASE_DIR为code目录(django_project的上级目录)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    def join_to_base_dir(path):
        return os.path.join(BASE_DIR, path)
    
    # 将code目录加入sys.path
    sys.path.append(BASE_DIR)
    # 调整apps路径为绝对路径
    sys.path.append(join_to_base_dir('django_project/apps'))
    

2. 明确指定测试目标

避免Django盲目递归查找测试,直接指定要运行的应用测试:
修改工作流中的测试命令,例如:

coverage run --branch --rcfile=.coveragerc ./manage.py test django_project.apps.django_app_1 django_project.apps.django_app_2 django_project.apps.django_app_3 -v 3 --noinput

或者用通配符批量指定所有apps下的测试:

coverage run --branch --rcfile=.coveragerc ./manage.py test django_project.apps.* -v 3 --noinput

3. 确认code/__init__.py的有效性

确保code目录下的__init__.py存在且无语法错误(你的目录结构中已经包含该文件),Python 3.12对包的识别要求更严格,空的__init__.py即可满足需求。


内容的提问来源于stack exchange,提问作者phrfpeixoto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:30:06