Django 1.8:为现有模式创建初始迁移
Django 1.8: Create initial migrations for existing schema
我启动了一个 django 1.8 项目,它使用了迁移系统。
不知何故,事情变得一团糟,所以我从数据库中删除了迁移文件夹和 table,现在我试图重建它们,但没有成功。
我有三个应用程序(3 models.py
个文件),模型完全反映了 tables!
到目前为止我发现的最佳方法是:
- 清除所有
migrations
文件夹。完成!
- 删除
django_migrations
table 中的所有内容。完成!
- 运行
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'")
我已经为这件事耗费了数小时。我怎么能初始化迁移,这样我就可以继续工作而不会每次都中断迁移?
为什么这么复杂?为什么没有简单的一行: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)。
以下是步骤(对于 运行 遇到此问题的任何人):
- 清空
django_migrations
table: delete from django_migrations;
- 对于每个应用程序,删除其
migrations
文件夹:rm -rf <app>/migrations/
- 重置 "built-in" 应用程序的迁移:
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
以使其工作。
如果您使用的是路由器,则可能存在问题。检查方法 allow_migrate
是否在 routers.py
中以正确的方式执行。尝试将 return 值始终设置为 True
,并检查它是否解决了问题,
def allow_migrate(self, db, app_label, model_name=None, **hints):
return True
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
属性。
注意初始值 - 自己验证来自 migrationsOLD
的所有 RunPython
操作,并在需要时将代码复制到新的初始迁移。
(--fake-initial
可选)将 initial=True
添加到所有新迁移 classes(如果已添加,也为 0002)。
- 在新迁移 class 中添加
replaces
属性。 (喜欢自己定制一个squashmigrations
)。将来自 <app>
的所有旧迁移放在那里
用makemigrations
验证一切。
断言"No changes detected"
检查 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 会将其视为已加载。
我启动了一个 django 1.8 项目,它使用了迁移系统。
不知何故,事情变得一团糟,所以我从数据库中删除了迁移文件夹和 table,现在我试图重建它们,但没有成功。
我有三个应用程序(3 models.py
个文件),模型完全反映了 tables!
到目前为止我发现的最佳方法是:
- 清除所有
migrations
文件夹。完成! - 删除
django_migrations
table 中的所有内容。完成! - 运行
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'")
我已经为这件事耗费了数小时。我怎么能初始化迁移,这样我就可以继续工作而不会每次都中断迁移?
为什么这么复杂?为什么没有简单的一行: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)。
以下是步骤(对于 运行 遇到此问题的任何人):
- 清空
django_migrations
table:delete from django_migrations;
- 对于每个应用程序,删除其
migrations
文件夹:rm -rf <app>/migrations/
- 重置 "built-in" 应用程序的迁移:
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
以使其工作。
如果您使用的是路由器,则可能存在问题。检查方法 allow_migrate
是否在 routers.py
中以正确的方式执行。尝试将 return 值始终设置为 True
,并检查它是否解决了问题,
def allow_migrate(self, db, app_label, model_name=None, **hints):
return True
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
属性。注意初始值 - 自己验证来自
migrationsOLD
的所有RunPython
操作,并在需要时将代码复制到新的初始迁移。(
--fake-initial
可选)将initial=True
添加到所有新迁移 classes(如果已添加,也为 0002)。- 在新迁移 class 中添加
replaces
属性。 (喜欢自己定制一个squashmigrations
)。将来自<app>
的所有旧迁移放在那里
用
makemigrations
验证一切。断言"No changes detected"
检查
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 会将其视为已加载。