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, обязательно выполняйте макетирование и переносите индивидуально для сторонних приложений, от которых зависят ваши приложения.