Системные проверки, миграции и тесты Django проходят локально, но не проходят в среде Docker CI / CD - PullRequest
2 голосов
/ 07 июня 2019

Проблема

Честно говоря, я просто запускаю этот в темноте, потому что я исчерпал все возможные пути, прежде чем спросить об этом.Я не уверен, в чем здесь проблема.

У меня есть приложение 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'.

Environment

Я использую 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

Я использую бесплатную версию GitLab, с GitLab Runner.

Это простой проект django.Существует один проект и одно приложение.

INSTALLED_APPS моего settings.conf выглядит следующим образом

# 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",
]

Шаги для локального запуска

Это будет пройти

  • 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

Затем я фиксирую все в ветке и запускаю 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                      

Модели

Теперь я понимаю, что это говорит о том, что он не может найти модели в приложении piano_gym_api.Но это не имеет смысла.

Модель здесь:

class LearnerEnrolledLesson(Model):
    is_enrolled = BooleanField(default=True)
    learner = ForeignKey("piano_gym_api.Learner", on_delete=CASCADE)
    # ---
    enrolled_school = ForeignKey("piano_gym_api.LearnerEnrolledSchool", on_delete=CASCADE)
    enrolled_course = ForeignKey("piano_gym_api.LearnerEnrolledCourse", on_delete=CASCADE)
    # ---
    school = ForeignKey(School, on_delete=CASCADE)
    course = ForeignKey(SchoolCourse, on_delete=CASCADE)
    lesson = ForeignKey(SchoolLesson, on_delete=CASCADE)
    order = IntegerField(default=1)

    REQUIRED_FIELDS = ["learner", "school", "course", "lesson", "enrolled_school", "enrolled_course"]

    objects = LearnerEnrolledLessonManager()

    class Meta:
        ordering = ("order",)
        unique_together = ("learner", "school", "course", "lesson", "enrolled_school", "enrolled_course", "order")

Единственное, что я здесь делаю, - это использование строк для ссылки на piano_gym_api.LearnerEnrolledSchool и piano_gym_api.LearnerEnrolledCourse.

Это сделано только потому, что в этих моделях есть функция, которая возвращает LearnerEnrolledLesson, и это круговая зависимость, поэтому я должен ссылаться на модели без использования пути импорта.

Обращение за помощью

Я понятия не имею, почему это происходит в моей среде док-станции CI / CD.Я не делаю ничего другого.Мой settings.py не меняется между средой разработки и средой ci / cd.И, шаги точно такие же.

Что я мог здесь делать не так?

1 Ответ

0 голосов
/ 23 июня 2019

Я нашел решение для этого, которое было невероятно тонким.

Итак, прежде всего, я хочу поблагодарить кого-то по имени Mark ♦ из Python Discord Channel .Благодаря их усилиям, сидящим со мной и проходящим через то, через что я работал, мы смогли диагностировать это.

Проблема здесь была тонкой, потому что в sqlite3 проблем не было.Однако, когда я перешел на postgresql, возникла проблема.

Проблема заключалась в том, что я не делал этого, чтобы мои модели были доступны.

Django требует, чтобы модели существовали на пути

  • django_project_name/django_app_name/models.py

или

  • django_project_name/django_app_name/models/

Моя структура каталогов на самом деле выглядит следующим образом

├── requirements.txt
├── manage.py
├── django_app_name
│   ├── models
│   │   └── __init__.py
│   ├── urls.py
│   └── versions
│       ├── __init__.py
│       └── v1
│           ├── __init__.py
│           ├── models
│           │   ├── __init__.py
│           │   └── ...
│           └── views
│               ├── __init__.py
│               └── ...
└── django_project_name
    └── ...

Проблема здесь в том, что для создания версионной структуры каталогов я переместил свои модели в django_project_name/django_app_name/versions/v1/

Из-за этого Django не смог найти модели, потому что я не был явносделать их доступными через файл models.py или каталог models, который ожидался в приложении Django.

Вот почему я получаю сообщение об ошибке, что Django не может найти конкретные модели, несмотря на то, что онитам.

Чтобы исправить это решение, мне пришлось явным образом раскрыть их, экспортировав их ссылки в файл django_project_name/django_app_name/models/__init__.py.

Это выглядело примерно так:

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

И с этим я смог получитьмодели будут доступны для makemigrations и migrate.

Очень тонко:)

...