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
В связи с этим два вопроса:
Как обойти такую ошибку последовательного применения миграций системой django?
Как в таком случае проводить миграции БД на боевом сервере чтобы сохранить текущую информацию в БД??
Ответы (1 шт):
Во время миграции не должно быть в коде обращений к моделям БД.
В предложенном решении автор указывает на то, что:
"Когда происходит миграция в коде не должно быть работы с моделями, и чтобы этого избежать создайте функцию для проверки статуса миграции".
Например, в коде 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