Django 系统检查、迁移和测试在本地通过,但在 Docker CI/CD 环境中失败

Gen*_*per 5 python django continuous-integration gitlab docker

问题

老实说,我只是把这个问题抛到了黑暗中,因为在问这个问题之前我已经用尽了所有可能的途径。我不确定这里出了什么问题。

我有一个 Django 应用程序,可以在本地运行完全正常。我可以运行迁移。我在本地对此进行了详细的开发,模型、测试或任何功能都没有出现任何问题。

这里的问题是,当我使用 GitLab 的 CI/CD Runner 并执行与我在本地执行的完全相同的步骤时,我会得到此输出。

ERRORS:
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledCourse', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_course was declared with a lazy reference to 'piano_gym_api.learnerenrolledcourse', but app 'piano_gym_api' doesn't provide model 'learnerenrolledcourse'.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledSchool', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_school was declared with a lazy reference to 'piano_gym_api.learnerenrolledschool', but app 'piano_gym_api' doesn't provide model 'learnerenrolledschool'.
Run Code Online (Sandbox Code Playgroud)

环境

我正在使用 Python 3.7 和 Django 2.2。我的依赖项如下所示:

certifi==2019.3.9
chardet==3.0.4
coreapi==2.3.3
coreschema==0.0.4
Django==2.2
django-cors-headers==3.0.2
django-extensions==2.1.7
djangorestframework==3.9.4
djangorestframework-jwt==1.11.0
gunicorn==19.9.0
idna==2.8
itypes==1.1.0
Jinja2==2.10.1
lxml==4.3.3
MarkupSafe==1.1.1
music21==5.5.0
PyJWT==1.7.1
pytz==2019.1
requests==2.22.0
six==1.12.0
sqlparse==0.3.0
uritemplate==3.0.0
urllib3==1.25.3
whitenoise==4.1.2
Run Code Online (Sandbox Code Playgroud)

GitLab我正在使用,的免费版本GitLab Runner

这是一个简单的 django 项目。有一个项目和一个应用程序。

settings.conf的 INSTALLED_APPS 看起来像这样

# Application definition
INSTALLED_APPS = [
    # Django Default
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # Third-Party Apps
    "corsheaders",
    "django_extensions",
    "rest_framework",
    "rest_framework.authtoken",
    "whitenoise.runserver_nostatic",
    # Custom Apps
    "piano_gym_api",
]
Run Code Online (Sandbox Code Playgroud)

本地运行的步骤

这会过去

  • pip3 install virtualenv
  • virtualenv -p python3 venv
  • source venv/bin/activate
  • pip3 install -r requirements.txt
  • python3 manage.py makemigrations piano_gym_api
  • python3 manage.py migrate
  • python3 manage.py test

在 GitLab CI/CD 中运行的步骤

这会失败

我已经安装了GitLab Runner

.gitlab-ci.yml在根目录中创建了一个文件。它所拥有的只是这个:

stages:
  - test

api-test:
  stage: test
  image: python:3.7
  script:
    - cd piano_gym_back_end
    # Create environment for python
    - pip3 install virtualenv
    - virtualenv -p python3 venv
    - source venv/bin/activate
    - pip3 install -r requirements.txt
    # Set up and run tests
    - python3 manage.py makemigrations piano_gym_api
    - python3 manage.py migrate
    - python3 manage.py test
Run Code Online (Sandbox Code Playgroud)

然后我将所有内容提交到分支上并运行 gitlab-runner exec docker api-test

然后遍历所有内容并输出

$ python3 manage.py makemigrations piano_gym_api
SystemCheckError: System check identified some issues:

ERRORS:
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledCourse', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_course was declared with a lazy reference to 'piano_gym_api.learnerenrolledcourse', but app 'piano_gym_api' doesn't provide model 'learnerenrolledcourse'.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledSchool', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_school was declared with a lazy reference to 'piano_gym_api.learnerenrolledschool', but app 'piano_gym_api' doesn't provide model 'learnerenrolledschool'.
ERROR: Job failed: exit code 1
FATAL: exit code 1                      
Run Code Online (Sandbox Code Playgroud)

楷模

现在我明白这表明它无法在应用程序中找到模型piano_gym_api。但这没有意义。

这里的模型是:

ERRORS:
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledCourse', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_course: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_course was declared with a lazy reference to 'piano_gym_api.learnerenrolledcourse', but app 'piano_gym_api' doesn't provide model 'learnerenrolledcourse'.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E300) Field defines a relation with model 'piano_gym_api.LearnerEnrolledSchool', which is either not installed, or is abstract.
piano_gym_api.LearnerEnrolledLesson.enrolled_school: (fields.E307) The field piano_gym_api.LearnerEnrolledLesson.enrolled_school was declared with a lazy reference to 'piano_gym_api.learnerenrolledschool', but app 'piano_gym_api' doesn't provide model 'learnerenrolledschool'.
Run Code Online (Sandbox Code Playgroud)

我在这里做的唯一一件事就是使用字符串来引用piano_gym_api.LearnerEnrolledSchoolpiano_gym_api.LearnerEnrolledCourse

这样做只是因为这些模型有一个返回 a 的函数,LearnerEnrolledLesson这是一个循环依赖项,所以我必须在不使用导入路径的情况下引用模型。

寻求帮助

我不知道为什么这在我的 CI/CD docker 环境中失败。我没有做任何不同的事情。我的settings.py开发环境和 ci/cd 环境之间没有变化。而且,步骤完全相同。

我在这里可能做错了什么?

Gen*_*per 4

我找到了解决这个问题的方法,这是非常微妙的。

\n\n

首先,我要感谢Mark \xe2\x99\xa6来自Python Discord Channel的某人。感谢他们与我坐下来并回顾我所经历的事情的努力,我们能够诊断出这一点。

\n\n

这里的问题很微妙,因为sqlite3没有任何问题。然而,当我迁移到时,postgresql问题就出现了。

\n\n

具体问题是我没有制作它,所以我的模型可用。

\n\n

Django 要求模型存在于路径中

\n\n
    \n
  • django_project_name/django_app_name/models.py
  • \n
\n\n

或者

\n\n
    \n
  • django_project_name/django_app_name/models/
  • \n
\n\n

我的目录结构实际上是这样的

\n\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 requirements.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 manage.py\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 django_app_name\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 models\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 urls.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 versions\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 v1\n\xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 models\n\xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 views\n\xe2\x94\x82\xc2\xa0\xc2\xa0             \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0             \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 django_project_name\n \xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里的问题是,为了创建版本化的目录结构,我已将模型移入django_project_name/django_app_name/versions/v1/

\n\n

因此,Django 无法找到模型,因为我没有通过Django 应用程序中预期的models.py文件或目录明确地提供它们。models

\n\n

这就是为什么我会收到 Django 无法找到特定模型的错误,尽管它们在那里。

\n\n

为了修复这个解决方案,我必须通过导出django_project_name/django_app_name/models/__init__.py文件中的引用来显式公开它们。

\n\n

看起来像这样:

\n\n
# REQUIRED!!!\n# Django requires models that are being used to be exposed in this models\n# directory\n# Because we have opted to use the `versions` folder for storing the structure\n# of our project, that means we need to surface those models explicitly here in\n# order to remove the possibility of a missing model during the `makemigrations`\n# and `migrate` commands\nfrom django_app_name.versions.v1.models.example_model_one import *\nfrom django_app_name.versions.v1.models.example_model_two import *\nfrom django_app_name.versions.v1.models.example_model_three import *\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样我就可以让我的模型可用于makemigrationsmigrate

\n\n

非常微妙:)

\n