Django 1.8: создать начальные миграции для существующей схемы
Я начал проект django 1.8, который использует систему миграции.
Как-то по пути все стало беспорядочно, поэтому я удалил папки миграции и таблицу из БД, и теперь я пытаюсь их восстановить, без успеха.
У меня есть три приложения (3 models.py
файлы), и модели отражают таблицы ТОЧНО!
Лучший подход, который я нашел до сих пор, заключался в следующем:
- Удалите все папки
migrations
. Готово!
- Удалить все из таблицы
django_migrations
. Готово!
- Запустите
python manage.py makemigrations --empty <app>
для каждого приложения. Готово!
- Запустите
python manage.py migrate --fake
. Готово! (хотя он работает, только если я запускаю его после каждой команды makemigrations
.
Теперь я добавляю новое поле, запускаю команду makemigrations
, и я получаю следующую ошибку:
django.db.utils.OperationalError: (1054, "Unknown column 'accounts_plan.max_item_size' in 'field list'")
Я сжигаю ЧАСЫ по этому поводу. Как h ** l можно инициализировать миграцию, чтобы я мог продолжать работать без прерываний миграции каждый раз?
Почему это так сложно? Почему нет простой однострочной линии: initiate_migrations_from_schema
?
EDIT:
Теперь все становится еще более неприятно. Я усекал таблицу django_migrations
и удалил всю папку migrations
.
Теперь я пытаюсь запустить python manage.py migrate --fake-initial
(что-то, что я нашел в документах DEV), так что он настраивает все внутренние приложения Django (auth, session и т.д.), И я получаю:
(1054, "Unknown column 'name' in 'django_content_type'")
.
Теперь этот "столбец" не является реальным столбцом. Это a @property
, определенное в приложении Django contenttypes
. ЧТО ЗДЕСЬ ПРОИСХОДИТ? Почему он идентифицирует свойство name
как реальный столбец?
Ответы
Ответ 1
Наконец-то он заработал, хотя я не знаю, почему и надеюсь, что он будет работать в будущем.
После многочисленных испытаний и прохождения через сайт Django dev (ссылка).
Вот шаги (для тех, кто сталкивается с этой проблемой):
- Очистить таблицу
django_migrations
: delete from django_migrations;
- Для каждого приложения удалите его папку
migrations
: rm -rf <app>/migrations/
- Reset миграции для "встроенных" приложений:
python manage.py migrate --fake
- Для каждого запуска приложения:
python manage.py makemigrations <app>
. Позаботьтесь о зависимостях (модели с ForeignKey должны запускаться после их родительской модели).
- Наконец:
python manage.py migrate --fake-initial
После этого я запустил последнюю команду без флага --fake-initial
, чтобы убедиться.
Теперь все работает, и я могу нормально использовать систему миграции.
Я уверен, что я не единственный, кто сталкивается с этой проблемой. Он должен быть документирован лучше и даже упрощен.
Обновление для пользователей Django 1.9:
У меня был этот сценарий снова с Django 1.9.4, а шаг 5 не удалось.
Все, что мне нужно было сделать, это заменить --fake-initial
на --fake
, чтобы он работал.
Ответ 2
Я столкнулся с этим сценарием, но мне никогда не приходилось отказываться от базы данных, чтобы решить эту проблему. Обычно я удаляю папку миграции из приложения и удаляю записи миграции из базы данных.
Я бы попытался запустить make migrations по одному приложению за раз. Если какое-либо приложение полагается на другие таблицы, очевидно, они добавляются последними.
Также я обычно запускаю python manage.py makemigrations, тогда просто python manage.py migrate Даже при начальной миграции он отлично работает с Django 1.7 и 1.8.
Ответ 3
django..., 1.8, 1.9,...
То, что вы хотите достичь, это раздавить существующие миграции и использовать их для замены.
Как сделать это правильно без использования какой-либо команды при выпуске (случай без влияния на базу данных и сотрудников).
-
Для каждого приложения избавьтесь от своей папки миграции:
mv <app>/migrations/ <app>/migrationsOLD/
-
Для каждого приложения: python manage.py makemigrations <app>
.
-
Настройте каждую новую миграцию:
-
если у вас есть сложное приложение или другие приложения и связанные модели между ними, чтобы избежать CircularDependencyError
или ValueError: Unhandled pending operations for models
:
подготовьте вторую пустую миграцию в <app>
0002_initial2.py
(добавьте зависимость от app_other::0001_initial.py
и <app>
:: 0001_initial.py
- все ForeignKey, M2M, связанные с моделями, созданными на этапе миграции 0001 в других приложениях)
Все должно быть в порядке - иногда для этого требуется больше миграций. Позаботьтесь об атрибуте dependencies
здесь в каждой миграции.
-
позаботьтесь о начальных значениях - проверьте все RunPython
действия из migrationsOLD
и скопируйте код в новую начальную миграцию, если это необходимо.
-
(необязательно для --fake-initial
) Добавьте initial=True
ко всем новым классам миграции (0002 тоже, если был добавлен).
- Добавить атрибут
replaces
в новый класс миграции. (например, собственный пользовательский squashmigrations
). Поместите туда все старые миграции из <app>
-
Проверьте все с помощью makemigrations
.
утвердить "Обнаружено никаких изменений"
-
Убедитесь, что migrate -l
показывает [x] всюду
утверждать подобное:
[X] 0001_initial
[X] 0002_initial2 (102 сжатые миграции)
Пример:
Для старых:
0001_initial.py
0002_auto.py
...
0103_auto.py
подготовить:
0001_initial.py
0002_initial2.py (optional but sometimes required to satisfy dependency)
и добавьте к replaces
для последнего (0002 здесь, может быть 0001):
replaces = [(b'<app>', '0002_auto.py'), ..., (b'<app>', '0103_auto.py')]
0001_initial.py следует называть так же, как старый.
0002_initial2.py является новым, но он заменяет старые миграции, поэтому Django будет обрабатывать его как загруженный.
Ответ 4
Если вы используете маршрутизаторы, может возникнуть проблема. Проверьте метод allow_migrate
, если он правильно выполнен в routers.py
. Попробуйте установить возвращаемое значение всегда как True
и проверить, разрешает ли он проблему,
def allow_migrate(self, db, app_label, model_name=None, **hints):
return True
Ответ 5
Если вы все еще получаете эту ошибку при обновлении до Django 1.8, обязательно выполняйте макетирование и переносите индивидуально для сторонних приложений, от которых зависят ваши приложения.