Django. Миграции в БД на боевом сервере. Правильный способ обновления структуры серверной БД

В ходе разработки Django-проекта появилась проблема миграций в БД. Разработка ведется на нескольких ПК с общим репозиторием кода и его синхронизацией при обновлении.

Суть проблемы:

Было выполнено несколько преобразований структуры одной из таблиц БД с переименованием и удалением/добавлением столбцов - полей модели. После синхронизации репозитория на другом ПК как применение, так и отображение миграций в БД выпадает исключение о несуществующем столбце в БД.

    Идет выполнение: manage.py makemigrations
Traceback (most recent call last):
  File "...\lib\site-packages\django\db\backends\utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "...\lib\site-packages\django\db\backends\sqlite3\base.py", line 396, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such column: app_department.shortName

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "...\manage.py", line 17, in <module>
    execute_from_command_line(sys.argv)
  File "...\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "...\lib\site-packages\django\core\management\__init__.py", line 377, in execute
    django.setup()
  File "...\lib\site-packages\django\__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "...\lib\site-packages\django\apps\registry.py", line 114, in populate
    app_config.import_models()
  File "...\lib\site-packages\django\apps\config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "...\Python37_64\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File ".\app\models.py", line 133, in <module>
    DEPARTMENT = [(dep.shortName, dep.depName) for dep in Department.objects.all()]
  File "...\lib\site-packages\django\db\models\query.py", line 276, in __iter__
    self._fetch_all()
  File "...\lib\site-packages\django\db\models\query.py", line 1261, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "...\lib\site-packages\django\db\models\query.py", line 57, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "...\lib\site-packages\django\db\models\sql\compiler.py", line 1144, in execute_sql
    cursor.execute(sql, params)
  File "...\lib\site-packages\django\db\backends\utils.py", line 100, in execute
    return super().execute(sql, params)
  File "...\lib\site-packages\django\db\backends\utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "...\django\db\backends\utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "...\lib\site-packages\django\db\backends\utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "...\lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "...\lib\site-packages\django\db\backends\utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "...\django\db\backends\sqlite3\base.py", line 396, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such column: app_department.shortName

В связи с этим два вопроса:

  1. Как обойти такую ошибку последовательного применения миграций системой django?

  2. Как в таком случае проводить миграции БД на боевом сервере чтобы сохранить текущую информацию в БД??


Ответы (1 шт):

Автор решения: JBlack

Во время миграции не должно быть в коде обращений к моделям БД.

В предложенном решении автор указывает на то, что:

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

Например, в коде models.py используется выборка из БД:

from . import myutils
...
if myutils.is_migration(): # во время миграций нет обращения к моделям БД
    TYPES = {}
else:
    TYPES = { rec.dictKey: (rec.shortName, rec.fullName) for rec in Type.objects.all() }

Функция is_migration() в myutils.py:

import sys
...
def is_migration():
    ''' Проверка аргументов командной строки на наличие миграции '''
    return 'makemigrations' in sys.argv or 'migrate' in sys.argv
→ Ссылка