ChatGPT解决这个技术问题 Extra ChatGPT

Django migrate --fake 和 --fake-initial 解释

我已经使用 Django 大约 2 年了,并且有一个我一直害怕使用的功能:伪造迁移。

我几乎到处都看过,我能获得的最多信息来自 documentation,其中指出:

- 伪造的

告诉 Django 将迁移标记为已应用或未应用,但无需实际运行 SQL 来更改数据库模式。这是为了让高级用户在手动应用更改时直接操纵当前的迁移状态;请注意,使用 --fake 存在将迁移状态表置于需要手动恢复以使迁移正确运行的状态的风险。

--假初始

如果具有由该迁移中的所有 CreateModel 操作创建的所有模型的名称的所有数据库表已经存在,则允许 Django 跳过应用程序的初始迁移。此选项适用于首次对已使用迁移的数据库运行迁移时使用。但是,此选项不会检查匹配表名之外的匹配数据库模式,因此只有在您确信现有模式与初始迁移中记录的内容匹配时才能安全使用。

我大致了解了为什么要使用此功能。但是,我不明白它说这仅适用于高级用户的部分。

有人可以解释幕后发生的事情以及为什么需要手动恢复。

笔记

我不是在寻找伪造迁移时运行的确切原始 SQL 查询。我只是在寻找幕后发生的事情的一般概念,也许是一个示例,说明为什么伪造迁移会导致 makemigrations 无法正常工作的状态。

我认为值得一提的是,当您运行 --fake 时,是否将迁移标记为已应用,在 django_migrations 表中定义,Django 使用迁移文件的 name 跟踪应用程序的所有已应用迁移以及何时应用。我花了一段时间才弄清楚这一点,因为文档并不清楚我在这里介绍的这个细节。

h
hynekcer

如果您需要将具有相似模型的两个分支组合或在它们之间切换,则它与类似于源代码 (git) 中的合并冲突的数据库问题有关。没有人故意喜欢它。

想象一下,您上周开始修改应用程序,可能是因为您发现了一个错误,或者您通过字段或表格扩展了应用程序。今天您收到了更新,但遇到了问题,因为有一个迁移添加了一个仍在您的数据库中的字段,您只能应用该迁移的其他部分。您可以通过运行查看迁移的 SQL 内容

./manage sqlmigrate some_app 0007_new_migration >customized-some_app-0007_new_migration.sql

将内容与上周所做的更改进行比较,并删除或注释掉仍然应用且不能重复的命令。手动运行所有剩余的 SQL。标记该迁移,就像它会自动应用一样:

./manage migrate --fake some_app 0007_new_migration

如果您破坏了某些东西,可能没有人可以帮助您,因为迁移系统不会更多地了解数据库的当前状态。因此,做备份、写笔记、使用沙箱并精确工作。

编辑:迁移表 django_migrations 是应用于所有应用的迁移的简单列表。此表中的行应始终与数据库结构处于同步状态。可以通过普通的 migrate 应用迁移。 (或通过反向迁移到较旧状态而未应用,当然通常会丢失一些数据)虚假迁移仅将更改应用于 django_migrations 表。

me => select * from django_migrations;
 id | app      |          name           |            applied            
----+----------+-------------------------+-------------------------------
  1 | some_app | 0001_initial            | 2017-10-16 06:11:07.31249+02
  2 | some_app | 0002_auto_20171016_1905 | 2017-10-17 02:05:48.979295+02

迁移(文件)是对增量更改的描述,也是可以评估自上次迁移以来 models.py 之间差异的信息,在运行 makemigrations 时进行比较。在某些表最初不受管理并且以后可以管理的情况下也足够了。 (因此也会记录非托管表。)

编辑: 一个示例:如何使用带有 --fakesqlmigratefix a broken database by migrations(重新创建已删除的表)。

编辑: 示例:如果您决定删除某个应用程序的表并通过 migrate 重新创建它们(请注意并在下面查看我的评论),您可能还想重置该应用程序的所有迁移首先,包括初始迁移,使用伪迁移名称“zero”。
./manage migrate --fake some_app zero


感谢你的回答!它帮助我看到了伪造迁移的真实情况,但我仍然想知道在伪造迁移时幕后发生了什么。
@hynekcer 我对您上次的编辑有疑问,当它们与我的数据库历史同步时,为什么我要“重置所有迁移”?最近我遇到了类似的问题,将独特的属性添加到表中的一行。当我运行迁移时,我收到错误:“ProgrammingError:关系“...唯一”已经存在”,但是当我删除所有迁移并重播此步骤时,它通过了吗?我必须指出,我的两个项目都在同一个数据库上工作,并且我在两个应用程序中都添加了唯一属性。
@Unknown123我应该在最后一个示例中添加一些警告“并且您知道自己在做什么”,例如,如果它正在开发中而没有重要数据并且同步被严重破坏以至于无法进行向前或向后迁移,那么假迁移到“零”并删除一些表可能是一个更好的解决方案,然后是慢速编辑 sqlmigrate 的结果,也比快速删除整个数据库更好。
如果您的两个项目在同一个数据库上工作,那么使用相同的 models.py 和相同的迁移目录很重要。在一个项目中迁移的内容也将在第二个项目中迁移。如果无法使用通用模型,那么如果可能会很糟糕,并且您永远无法在第二个数据库中运行迁移并且仅手动运行 sqlmigrate 的一小部分并设置 Meta: managed=False。
事实上,在很多情况下你需要伪造迁移。特别是当您想在另一台服务器中使用来自一台服务器的数据库转储时。当您遇到难以调试且只能在生产服务器中重现的错误时,伪造非常有用。由于 git 冲突而弄乱迁移文件是因为 .gitignore 文件配置错误。作为伪造迁移的用例,这不是一个很好的例子