我进行了一个迁移,添加了一个新表并想要还原它并删除迁移,而不创建新的迁移。
我该怎么做?是否有恢复上次迁移的命令,然后我可以简单地删除迁移文件?
您可以通过 migrating to the previous migration 恢复。
例如,如果您的最后两次迁移是:
0010_previous_migration
0011_migration_to_revert
然后你会这样做:
./manage.py migrate my_app 0010_previous_migration
您实际上不需要使用完整的迁移名称,数量就足够了,即
./manage.py migrate my_app 0010
然后您可以删除迁移 0011_migration_to_revert
。
如果您使用的是 Django 1.8+,则可以显示所有迁移的名称
./manage.py showmigrations my_app
要反转应用程序的所有迁移,您可以运行:
./manage.py migrate my_app zero
Alasdair 的回答涵盖了基础知识
通过 ./manage.py showmigrations 确定您想要的迁移
使用应用名称和迁移名称进行迁移
但需要指出的是,并非所有迁移都可以逆转。如果 Django 没有进行反转的规则,就会发生这种情况。对于您在 ./manage.py makemigrations
之前自动迁移的大多数更改,可以撤消。但是,自定义脚本需要同时编写正向和反向,如下面的示例所述:
https://docs.djangoproject.com/en/1.9/ref/migration-operations/
如何进行无操作反转
如果您有一个 RunPython
操作,那么您可能只是想退出迁移而不编写逻辑上严格的反转脚本。以下来自文档(上方链接)的示例的快速破解允许这样做,使数据库保持与应用迁移后相同的状态,即使在反转它之后也是如此。
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
]
这适用于 Django 1.8、1.9
更新:编写此代码的更好方法是将上面代码段中的 lambda apps, schema_editor: None
替换为 migrations.RunPython.noop
。这些在功能上都是一样的。 (归功于评论)
RunPython.noop
而不是内联 lambda 或等效项:docs.djangoproject.com/en/1.8/ref/migration-operations/…
migrations.RunPython(forwards_func, migrations.RunPython.noop)
。需要在功能上进行检查。有时应该将其添加为答案或对此进行编辑。
在还原之前不要删除迁移文件。我犯了这个错误,没有迁移文件,数据库不知道要删除什么。
python manage.py showmigrations
python manage.py migrate {app name from show migrations} {00##_migration file.py}
If you want to revert all migrations,使用 zero
作为迁移的名称:
python manage.py migrate app_name_here zero
删除迁移文件。一旦所需的迁移在您的模型中......
python manage.py makemigrations
python manage.py migrate
这是我的解决方案,因为当您使用 RunPython
时,上述解决方案并未真正涵盖用例。
您可以通过 ORM 访问该表
from django.db.migrations.recorder import MigrationRecorder
>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})
因此,您可以查询表并删除与您相关的那些条目。这样您就可以进行详细修改。对于 RynPython
迁移,您还需要处理添加/更改/删除的数据。上面的例子只展示了如何通过 Djang ORM 访问表。
django.db.utils.ProgrammingError: relation "<relation name>" already exists
这样的错误消息,因此我输入了一个错误的 migrate --fake
,所以我尝试返回,然后得到 psycopg2.ProgrammingError: relation "<other <relation name>" does not exist
THANKS
我在 1.9.1 中执行了此操作(删除创建的最后一个或最新的迁移):
rm
然后,我能够创建以我刚刚删除的迁移编号(在本例中为 11)开始的新迁移。
要恢复迁移:
python manage.py migrate <APP_NAME> <MIGRATION_NUMBER_PREFIX>
MIGRATION_NUMBER_PREFIX
是您要恢复到的迁移的数字前缀,例如 0001
转至 0001_initial.py
迁移。然后您可以删除该迁移。
您可以使用零作为迁移编号来还原应用程序的所有迁移。
您可以做的另一件事是删除手动创建的表。
除此之外,您还必须删除该特定迁移文件。此外,您必须删除 django-migrations 表中与该特定迁移相关的特定条目(可能是您的最后一个)。
您可以通过迁移到以前的迁移来恢复。
例如使用以下命令:
./manage.py migrate example_app one_left_to_the_last_migration
然后删除 last_migration
文件。
如果您在恢复迁移时遇到问题,并且不知何故弄乱了它,您可以执行 fake
迁移。
./manage.py migrate <name> --ignore-ghost-migrations --merge --fake
对于 django 版本 1.7 这将在 south_migrationhistory
表中创建条目,您需要删除该条目。
现在,您将能够轻松恢复迁移。
PS:我被困了很长时间,执行虚假迁移然后恢复帮助我解决了问题。
如果 Alasdair 的最佳答案没有帮助,则此答案适用于类似情况。 (例如,如果每次新迁移都会很快再次创建不需要的迁移,或者如果它处于无法恢复的更大迁移中,或者表已被手动删除。)
...删除迁移,而不创建新的迁移?
TL;DR:您可以删除一些最后恢复(混淆)的迁移,并在修复模型后创建一个新迁移。您也可以使用其他方法将其配置为不通过 migrate 命令创建表。必须创建最后一个迁移,使其与当前模型匹配。
任何人都不想为必须存在的模型创建表的情况:
A)没有这样的表不应该存在于任何机器上的任何数据库中并且没有条件
何时:它是仅为其他模型的模型继承而创建的基础模型。
解决方案:设置类 Meta: abstract = True
B)该表很少通过其他方式或以特殊方式手动创建。
解决方案:使用 class Meta: managed = False 迁移已创建,但从未使用,仅在测试中使用。迁移文件很重要,否则数据库测试无法运行,从可重现的初始状态开始。
C) 该表仅在某些机器上使用(例如在开发中)。
解决方案:将模型移动到新的应用程序中,仅在特殊条件下才添加到 INSTALLED_APPS 或使用条件类 Meta:managed = some_switch。
D) 该项目在 settings.DATABASES
中使用多个数据库
解决方案:使用方法 allow_migrate 编写一个数据库路由器,以区分应该创建表和不创建表的数据库。
迁移是在 Django 1.9+ 的所有情况 A)、B)、C)、D) 中创建的(并且仅在 Django 1.8 的情况下 B、C、D 中),但仅在适当的情况下或可能永远不会应用于数据库要求如此。从 Django 1.8 开始,运行测试就需要迁移。迁移记录完整的相关当前状态,即使对于 Django 1.9+ 中 managed=False 的模型,也可以在托管/非托管模型之间创建 ForeignKey 或稍后使模型 managed=True。 (这个问题是在 Django 1.8 的时候写的。这里的一切都应该对 1.8 到当前 2.2 之间的版本有效。)
如果最后一次迁移不容易恢复,那么可以谨慎地(在数据库备份之后)执行 fake revert ./manage.py migrate --fake my_app 0010_previous_migration
,手动删除表。
如有必要,从固定模型创建固定迁移并应用它而不更改数据库结构 ./manage.py migrate --fake my_app 0011_fixed_migration
。
有一个很好的图书馆可以使用它的名为 djagno-nomad,虽然与提出的问题没有直接关系,但想到分享这个,
场景:大多数时候切换到项目时,我们觉得它应该恢复我们在当前分支上所做的更改,这正是这个库所做的,请在下面查看
https://pypi.org/project/django-nomad/
所有其他答案都非常适合回滚线性迁移。但是,当迁移是非线性的,即有多个叶子节点并且我们希望只回滚一条路径时,我们可以通过以下方式进行:
X
/ \
A B [A and B can represent any number of linear migrations.]
\ /
Y (merge migration)
如果我们需要回滚 A、B 和 Y。那么我们可以按照其他答案状态的方式进行操作。即python manage.py migrate app X
。
但是,如果只需要取消应用一条路径,即回滚 B 和 Y,请执行以下步骤:
仅取消应用 Y。通过执行 python manage.py migrate app B(或 A;两者都有效)。暂时从项目位置删除迁移文件 A 和 Y。现在通过执行 python manage.py migrate app X 取消应用 B。
将迁移文件 A 和 Y 带到原始位置。现在,如果您愿意,您可以安全地删除未应用的迁移 B 和 Y。
要点是,如果文件存在于该位置,django 只能回滚迁移。如果您不想回滚迁移路径(即此处的 A),请在执行回滚时将其从项目位置移除。
第一:找到你的应用以前的迁移,
python mange.py showmigrations
例如:
bz
[X] 0001_initial
[ ] 0002_bazifff
如果你想回滚 0002_bazifff 迁移,
python manage.py migrate bz 0001_initial
如果要回滚 0001_initial 或全部
python manage.py migrate bz zero
似乎不能只回滚0001
'0010_previous_migration'
,我不知道您为什么会看到这种行为。/manage.py migrate my_app 0010
,只有0010
,而不是完整的文件名。之后,手动删除本地文件 appname/migrations/0011+,然后从 django_migrations db 表中手动删除 0011+ 的行。