如何恢复上次迁移?

我做了一个迁移,添加了一个新表,并希望恢复它并删除迁移,而不创建新的迁移。

我该怎么做?是否有恢复上次迁移的命令,然后我可以简单地删除迁移文件?

395290 次浏览

您可以通过迁移到上一个迁移恢复。

例如,如果您的最后两次迁移是:

  • 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

您可以做的另一件事是删除手动创建的表。

除此之外,您还必须删除该特定的迁移文件。此外,您还必须删除django迁移表中的特定条目(可能是您案例中的最后一个),它与该特定迁移相关。

Alasdair的回答涵盖了基础知识

  • 通过./manage.py showmigrations识别您想要的迁移
  • migrate使用应用名称和迁移名称

但需要指出的是,并非所有迁移可以都可以逆转。如果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。这在功能上是一样的。(归功于评论)

我在1.9.1中这样做了(删除最后一次或最新创建的迁移):

  1. rm <appname>/migrations/<migration #>*

    例子:rm myapp/migrations/0011*

  2. 登录到数据库并运行此SQL(本例中为postgres)

    delete from django_migrations where name like '0011%';

然后,我能够创建以我刚刚删除的迁移编号(在本例中为11)开始的新迁移。

这是我的解决方案,因为上述解决方案并没有真正涵盖用例,当你使用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访问表。

此答案适用于类似情况如果Alasdair的最高答案没有帮助。(例如,如果每次新迁移都会很快再次创建不需要的迁移,或者如果它处于无法恢复的更大迁移中,或者表已被手动删除。)

…删除迁移,而不创建新的迁移?

太长别读:您可以删除一些最后恢复(混乱)的迁移并创建一个新的修复模型后。您还可以使用其他方法通过迁移命令配置它不创建表必须创建最后一次迁移,使其与当前模型匹配


案件为什么任何人都不想为必须存在的模型创建表:

(一)没有这样的表应该存在于没有机器和没有条件的数据库中

  • 何时:它是仅为其他模型的模型继承而创建的基本模型。
  • 解决方案:套装class Meta: abstract = True

B)表很少创建,由其他东西或以特殊方式手动创建。

  • 解决方案:使用class Meta: managed = False
    迁移已创建,但从未使用过,仅在测试中使用。迁移文件很重要,否则数据库测试无法从可再现的初始状态开始运行。

C)该表仅在某些机器上使用(例如在开发中)。

  • 解决方案:将模型移动到仅在特殊条件下添加到INSTALLED_APPS的新应用程序或使用条件class 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+中具有托管=False的模型,迁移也会记录完整的相关当前状态,以便可以在托管/非托管模型之间创建ForeignKey,或者稍后可以使模型托管=True。(这个问题是在Django 1.8的时候写的。这里的所有内容都应该对1.8到当前2.2之间的版本有效。)

如果最后一次迁移不容易恢复,那么可以谨慎地(在数据库备份后)执行假恢复./manage.py migrate --fake my_app 0010_previous_migration,手动删除表。

如有必要,请从固定模型创建固定迁移并在不更改数据库结构./manage.py migrate --fake my_app 0011_fixed_migration的情况下应用它。

如果您在恢复迁移时遇到问题,并且以某种方式搞砸了它,您可以执行fake迁移。

./manage.py migrate <name> --ignore-ghost-migrations --merge --fake

对于django版本<1.7,这将在south_migrationhistory表中创建条目,您需要删除该条目。

现在,您将能够轻松地恢复迁移。

PS:我被困了很长时间,执行假迁移,然后返回帮助我。

在恢复之前不要删除迁移文件。我犯了这个错误,没有迁移文件,数据库不知道要删除什么。

python manage.py showmigrations
python manage.py migrate {app name from show migrations} {00##_migration file.py}

如果您想恢复所有迁移,使用zero作为迁移的名称:

python manage.py migrate app_name_here zero

删除迁移文件。一旦所需的迁移在您的模型中…

python manage.py makemigrations
python manage.py migrate

您可以通过迁移到上一个迁移来恢复。

例如使用下面的命令:

./manage.py migrate example_app one_left_to_the_last_migration

然后删除last_migration文件。

有一个很好的库使用它的所谓的djagno-游牧民族,虽然没有直接相关的问题问,想分享这个,

场景:大多数时候切换到项目时,我们觉得它应该恢复我们在当前分支上所做的更改,这正是这个库的作用,如下所示

https://pypi.org/project/django-nomad/

要恢复迁移:

python manage.py migrate <APP_NAME> <MIGRATION_NUMBER_PREFIX>

MIGRATION_NUMBER_PREFIX是您要恢复到的迁移的数字前缀,例如0001转到0001_initial.py迁移。然后您可以删除该迁移。

您可以使用zero作为迁移号来恢复应用程序的所有迁移。

首先:查找您的应用程序以前的迁移,

python manage.py showmigrations

eg:

bz
[X] 0001_initial
[ ] 0002_bazifff




如果您想要回滚0002_bazifff迁移,

python manage.py migrate bz 0001_initial

如果您想要回滚0001_initial所有

python manage.py migrate bz zero

好像不能只回滚0001

所有其他答案都非常适合回滚线性迁移。然而,当迁移是非线性的,即有多个叶节点,我们希望只回滚一条路径时,那么我们可以采用以下方法:

    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,请执行以下步骤:

  1. 通过执行python manage.py migrate app B (or A; both works)仅取消应用Y。
  2. 暂时从项目位置删除迁移文件A和Y。
  3. 现在通过执行python manage.py migrate app X来取消应用B。

将迁移文件A和Y带到原始位置。现在,如果您愿意,您可以安全地删除未应用的迁移B和Y。

要点是django只能在文件存在于该位置时回滚迁移。如果您不想回滚迁移路径(即此处的A),请在执行回滚时将其从项目位置中删除。