Django 1.8:为现有模式创建初始迁移

Django 1.8: Create initial migrations for existing schema

我启动了一个 django 1.8 项目,它使用了迁移系统。
不知何故,事情变得一团糟,所以我从数据库中删除了迁移文件夹和 table,现在我试图重建它们,但没有成功。

我有三个应用程序(3 models.py 个文件),模型完全反映了 tables!

到目前为止我发现的最佳方法是:

  1. 清除所有 migrations 文件夹。完成!
  2. 删除 django_migrations table 中的所有内容。完成!
  3. 运行 python manage.py makemigrations --empty <app> 每个应用程序。完成!
  4. 运行python manage.py migrate --fake。完毕! (虽然它只有在我 运行 每个 makemigrations 命令后它才有效。

现在我添加一个新字段,运行 makemigrations 命令,我收到以下错误:
django.db.utils.OperationalError: (1054, "Unknown column 'accounts_plan.max_item_size' in 'field list'")

我已经为这件事耗费了数小时。我怎么能初始化迁移,这样我就可以继续工作而不会每次都中断迁移?

为什么这么复杂?为什么没有简单的一行:initiate_migrations_from_schema?

编辑:
现在事情变得更糟了。我 运行 分类了 django_migrations table 并删除了所有 migrations 文件夹。
现在我尝试 运行 python manage.py migrate --fake-initial(我在 DEV 文档中找到的东西),这样它就设置了 Django 的所有 'internal' 应用程序(身份验证、会话等),我得到了:
(1054, "Unknown column 'name' in 'django_content_type'").
现在,这个 "column" 不是真正的专栏。它是 Django 的 contenttypes 应用程序中定义的 @property。这里发生了什么?为什么将 name 属性 识别为真正的列?

我 运行 遇到过这种情况,但我从来没有不得不删除数据库来解决它。通常我会从应用程序中删除迁移文件夹,并从数据库中删除迁移条目。

我会尝试 运行 一次迁移一个应用程序。如果任何应用程序依赖于其他表,显然最后添加它们。

另外我通常只是 运行, python manage.py makemigrations 然后 python manage.py migrate 即使是初始迁移,它也应该可以在 Django 1.7 和 1.8 上正常工作。

终于成功了,虽然我不知道为什么,但我希望它能在未来发挥作用。
经过多次试验并浏览 Django 的开发站点 (link)。
以下是步骤(对于 运行 遇到此问题的任何人):

  1. 清空 django_migrations table: delete from django_migrations;
  2. 对于每个应用程序,删除其 migrations 文件夹:rm -rf <app>/migrations/
  3. 重置 "built-in" 应用程序的迁移:python manage.py migrate --fake
  4. 对于每个应用 运行:python manage.py makemigrations <app>。处理依赖关系(具有 ForeignKey 的模型应该 运行 在其父模型之后)。
  5. 最后:python manage.py migrate --fake-initial

之后我 运行 最后一个命令没有 --fake-initial 标志,只是为了确定。

现在一切正常,我可以正常使用迁移系统了。

我敢肯定我不是唯一遇到此问题的人。必须更好地记录它,甚至简化它。

Django 1.9 用户更新:
我用 Django 1.9.4 再次遇到这种情况,第 5 步失败了。
我所要做的就是将 --fake-initial 替换为 --fake 以使其工作。

如果您使用的是路由器,则可能存在问题。检查方法 allow_migrate 是否在 routers.py 中以正确的方式执行。尝试将 return 值始终设置为 True,并检查它是否解决了问题,

def allow_migrate(self, db, app_label, model_name=None, **hints):
    return True

django ..., 1.8, 1.9, ...

您想要实现的是压缩现有迁移并使用替换它们。

发布时不使用任何命令如何正确完成(不影响数据库和同事的情况)。

  1. 对于每个应用程序,删除其迁移文件夹: mv <app>/migrations/ <app>/migrationsOLD/

  2. 对于每个应用 运行:python manage.py makemigrations <app>

  3. 自定义每个新迁移:

    • 如果您有一个 复杂的应用程序 ,或更多应用程序和它们之间的相关模型,以避免 CircularDependencyErrorValueError: Unhandled pending operations for models

      准备 <app> 0002_initial2.py 中的第二个空迁移(也将依赖 app_other::0001_initial.py<app>::0001_initial.py - 所有 ForeignKey,M2M与在其他应用程序的 0001 迁移步骤中创建的模型相关)

      一切都必须有序 - 有时需要更多的迁移来准备。在每个迁移中注意这里的 dependencies 属性。

    • 注意初始值 - 自己验证来自 migrationsOLD 的所有 RunPython 操作,并在需要时将代码复制到新的初始迁移。

    • --fake-initial 可选)将 initial=True 添加到所有新迁移 classes(如果已添加,也为 0002)。

    • 在新迁移 class 中添加 replaces 属性。 (喜欢自己定制一个squashmigrations)。将来自 <app>
    • 的所有旧迁移放在那里
  4. makemigrations验证一切。

    断言"No changes detected"

  5. 检查 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 会将其视为已加载。