使用Django South重置迁移历史的推荐方法是什么?

155

我使用South(0.7)和Django(1.1.2)积累了很多迁移,这些迁移开始在我的单元测试中占用了相当多的时间。我想重置基线并开始全新的迁移集。我已经查阅了South文档,进行了常规的Google/Stackoverflow搜索(例如,“django south (reset OR delete OR remove) migration history”),但没有找到明显的解决方法。

我考虑过一种方法,即通过“删除”South或手动“清除”历史记录(例如,清除数据库表,从migrations目录中删除迁移文件),然后重新运行:

./manage.py schemamigration southtut --initial

因此,如果有人以前做过这个,并且有一些建议或提示,那将非常感激。


有时候你需要手动将 __init__.py 添加到 appname/migrations - laike9m
2
你如何在1.7中重置迁移(使用内置迁移)? - Timo
1
@Timo:https://docs.djangoproject.com/en/dev/topics/migrations/#squashing-migrations 可能是一种方法。您也可以只删除*migrations/*目录并重新发出./manage.py makemigrations,但如果您不从新的数据库开始,将会发生糟糕的事情... - Jocelyn delalande
我认为squashmigrations是正确的答案。 - Julio Marins
7个回答

187
如果你需要有选择性地(仅针对一个应用程序)重置正在进行的迁移,this 对我有用。
rm <app-dir>/migrations/*
python manage.py schemamigration <app-name> --initial
python manage.py migrate <app-name> 0001 --fake  --delete-ghost-migrations

请不要忘记手动恢复其他应用程序上的任何dependencies,方法是在您的迁移类中的第一个属性下添加类似于depends_on = (("<other_app_name>", "0001_initial"),("<yet_another_app_name>", "0001_initial"))的行,将其添加到您的<app-dir>/migrations/0001_initial.py文件中。

然后,您可以按照this SO answer在其他环境中运行./manage.py migrate <app-name> --fake --delete-ghost-migrations。当然,如果您虚假删除或虚假migrate zero,则需要使用类似于this的迁移手动删除任何剩余的数据库表。

更加激进的选择是在生产环境服务器上运行./manage.py migrate --fake --delete-ghost-migrations,然后进行[my]sqldump。然后将该转储文件导入到需要迁移、完全填充的数据库的环境中的[my]sql中。我知道这是对South的亵渎,但这对我起作用了。

2
我真正想要的是“以models.py为准则,从那一点开始让我得到一个干净的版本”。因此保留从头开始设置部署或从现有部署中工作的能力。 - Bryce
1
这就是它的作用。 - hobs
2
@hobs 我在伪造新的初始迁移时遇到了“DependsOnUnknownMigration”错误。感谢您的评论,我可以找出应该更新depends_on语句所涉及到的这个应用程序。这确实是此处最好的答案。谢谢! :) - manu

121

编辑 - 在接下来的正式答案之前,请先仔细阅读下面@andybak所说的评论

@Dominique:您关于manage.py重置South的建议是危险的,如果项目中有任何第三方应用程序使用South,可能会破坏数据库,如@thnee所指出的那样。由于您的答案得到了这么多赞,我真的希望您能够编辑它,并至少添加一个关于此事的警告(最好是像@hobs方法一样,既方便又不影响其他应用程序)- 谢谢!- chrisv Mar 26 '13 at 9:09

正式答案如下:

首先,South作者在这里给出了一个回答:

只要您确保同时在所有部署中执行此操作,就不应该有任何问题。 就我个人而言,我会这样做:

    rm -r appname/migrations/ 
    ./manage.py reset south 
    ./manage.py convert_to_south appname 

请注意,“reset south” 部分会清除所有应用的迁移记录,因此请确保您运行了其他两行代码以清除所有应用程序或进行有选择性删除。

最后一行调用 convert_to_south 生成新的迁移并伪应用它(因为您的数据库已经有相应的表),在此过程中不需要删除所有应用的表格。

以下是我在需要摆脱所有这些不必要的开发迁移时在我的开发和生产服务器上执行的操作:

  1. 确保我们在两个端点上具有相同的数据库架构
  2. 在两个端点上删除每个迁移文件夹
  3. 在两个端点上运行 ./manage.py reset south(如帖子所说)= 清除south表格 *
  4. 在两个端点上运行./manage.py convert_to_south(假装 0001 迁移)
  5. 然后我可以重新开始制作迁移并推送服务器上的迁移文件夹

* 除非您只想清理其他应用程序中的一个应用程序,如果是这样,您需要编辑 south_history 表格并仅删除有关您应用的条目。


2
仅供记录,南方作者的回答如下:只要您确保同时在所有部署上执行此操作,就不应该有任何问题。个人建议执行以下步骤: rm -r appname/migrations/ ./manage.py reset south ./manage.py convert_to_south appname(请注意,“reset south”部分会清除所有应用程序的迁移记录,因此请确保对所有应用程序运行其他两行或进行选择性删除)。 - Adriaan Tijsseling
2
请注意,如果您删除了表,则需要使用 manage.py schemamigration app name --initial 而不是 convert_to_south。 - Adriaan Tijsseling
7
从 Django 1.5 开始,“reset” 管理命令已被删除。相反,您需要执行类似于 south.models.MigrationHistory.objects.all().delete() 的操作。 - Andrew B.
13
@Dominique:你关于 manage.py reset south 的建议是很危险的,如果项目中有任何第三方应用程序使用 south,则可能会破坏数据库,如下面的@thnee指出。由于你的答案有很多赞,我真的很感激如果你可以编辑它并至少添加一个警告,或者(更好的)改为反映@hobs的方法(同样方便但不影响其他应用程序)-谢谢! - chrisv
3
为什么这个帖子得到了很高的赞?你几乎永远不应该完全删除你的south_migrationhistory表,因为这会彻底破坏任何依赖于与之相关的迁移的应用程序,而你可能并不想去修改它们。Hob的答案是正确的。 - Cerin
显示剩余3条评论

54

感谢Dominique Guardiola和hobs的答案,它们帮助我解决了一个难题。不过在解决方案中还存在一些问题,以下是我的看法。

如果你有使用South的第三方应用程序(基本上所有东西都使用South),例如django-cms,那么使用manage.py reset south不是一个好主意。

reset south将删除您安装的所有应用程序的所有迁移历史记录。

现在考虑一下,如果您升级到最新版本的django-cms,它将包含像0009_do_something.py这样的新迁移。当您尝试在迁移历史记录中没有00010008的情况下运行该迁移时,South肯定会感到困惑。

更好/更安全的做法是只有选择性地重置您正在维护的应用程序。


首先,请确保您的应用程序在磁盘上的迁移和已在数据库上执行的迁移之间没有任何不同步。否则会头痛不已。

1. 删除我的应用程序的迁移历史记录

sql> delete from south_migrationhistory where app_name = 'my_app';

2. 删除我的应用程序的迁移

$ rm -rf my_app/migrations/

3. 为我的应用程序创建新的初始迁移

$ ./manage.py schemamigration --initial my_app

4. 模拟执行我的应用程序的初始迁移

这会将迁移插入south_migrationhistory,而不会触及实际的表:

$ ./manage.py migrate --fake my_app

其实步骤3和4只是manage.py convert_to_south my_app命令的更长变体,但在修改生产数据库这样微妙的情况下,我更喜欢拥有额外的控制权。


2
我编辑了我的答案,纳入了你发现的问题的修复(只是根据你的答案猜测),并在一个拥有数百万行数据的生产数据库上进行了测试。 - hobs
2
这就是我们正在做的事情。如果在第4步使用--delete-ghost-migrations选项,您可以省略第1步。 - tobych
2
@wadim 因此,步骤0:确保磁盘上的迁移和数据库中已执行的迁移之间没有不同步。 - thnee
@thnee 对的。值得一提的是,在步骤0中,您正在引用所有已安装的应用程序。您知道执行步骤0的简便方法吗? - wadim
@Bryce,“delete from”是在数据库 shell 中执行的原始 SQL。 - tadasajon
显示剩余3条评论

7

像thnee(参见她的回答)一样,我们采用了更为温和的方法来实现南部作者(Andrew Godwin)在其他地方引用的建议,并且我们在部署期间将代码库和数据库的操作分开处理,因为我们需要可重复的部署:

我们在代码中所做的:

# Remove all the migrations from the app
$ rm -fR appname/migrations
# Make the first migration (don't touch the database)
$ ./manage.py schemamigration appname --initial

一旦代码部署完成,我们需要对数据库进行哪些操作

# Fake the migration history, wiping out the rest
$ ./manage.py migrate appname --fake --delete-ghost-migrations

我认为我刚刚做了同样的事情,但是手动删除数据库条目,而不是使用--delete_ghoist-migrations。你的方法更好一些。 - wobbily_col

1

以下内容仅在您想要重置所有应用程序时适用。请在此操作之前备份所有数据库。如果有任何初始文件中的 depends_on,也请记下。

仅执行一次:

(1) find . -type d -name migrations -exec git rm -rf '{}' \;
(2) find . -type d -name migrations -exec rm -rf '{}' \;
(3) ./manage.py schemamigration <APP_NAME> --initial
(4) [GIT COMMIT]

在推送之前,尝试引导项目。然后,对于每台本地/远程机器,请应用以下步骤:

(5) [GIT PULL]
(6) ./manage.py reset south
(7) ./manage.py migrate --fake

对于想重新关联的每个应用程序,执行初始 (3)。请注意,重置 (6) 仅会删除迁移历史记录,因此不会对库造成任何伤害。虚假迁移 (7) 会恢复任何已安装的第三方应用程序的迁移历史记录。

1

如果您与作者不同,想要保留现有的迁移(即您想重置应用程序以及迁移历史记录,但保留实际迁移),那么您可以尝试这个链接:http://goo.gl/0ZnWm - mgalgs

0

从应用文件夹中删除必要的文件

实例路径

 cd /usr/local/lib/python2.7/dist-packages/wiki/south_migrations

wiki - 是我的应用程序


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接