【问题标题】:如何恢复上次迁移?
【发布时间】:2015-11-14 09:42:21
【问题描述】:

我进行了迁移,添加了一个新表,并且想要还原它并删除迁移,而不创建新迁移。

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

【问题讨论】:

    标签: django django-migrations


    【解决方案1】:

    首先:找到您的应用以前的迁移,

    python mange.py showmigrations

    例如:

    bz
     [X] 0001_initial
     [ ] 0002_bazifff
    
    
    

    如果您想回滚 0002_bazifff 迁移,

    python manage.py migrate bz 0001_initial

    如果你想回滚 0001_initialall

    python manage.py migrate bz zero

    好像不能回滚0001只有

    【讨论】:

      【解决方案2】:

      您可以通过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
      

      【讨论】:

      • 我已经看到了很多关于这个问题的答案,这些答案都是旧的,根本不再适用。 +1 因为这适用于 Django 1.8。
      • 用户通常不想删除迁移文件吗?我经常发现自己进行迁移,然后重新考虑它并在提交干净的东西之前重新创建它,所以我通常需要记住'rm path/to/0011_migration_to_revert.py'
      • @Ness 这只是“去迁移”。如果您不想再进行迁移,您还需要删除迁移文件。
      • 只要您使用的是您的实际迁移名称,而不是 '0010_previous_migration',我不知道您为什么会看到这种行为。
      • 使用 django 2.1,这对我有用:/manage.py migrate my_app 0010,只有0010,而不是完整的文件名。之后,手动删除本地文件 appname/migrations/0011+,然后从 django_migrations db 表中手动删除 0011+ 的行。
      【解决方案3】:

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

      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
      

      【讨论】:

        【解决方案4】:

        要恢复迁移:

        python manage.py migrate <APP_NAME> <MIGRATION_NUMBER_PREFIX>
        

        MIGRATION_NUMBER_PREFIX 是您要恢复到的迁移的号码前缀,例如0001 转至0001_initial.py 迁移。那么您可以删除该迁移。

        您可以使用zero 作为您的迁移编号来还原应用的所有迁移。

        【讨论】:

          【解决方案5】:

          有一个很好的库可以使用它的名为 djagno-nomad,虽然与提出的问题没有直接关系,但还是想分享一下,

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

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

          【讨论】:

            【解决方案6】:

            您可以通过迁移到以前的迁移来恢复。

            例如使用下面的命令:

            ./manage.py migrate example_app one_left_to_the_last_migration
            

            然后删除last_migration文件。

            【讨论】:

              【解决方案7】:

              如果您在恢复迁移时遇到问题,并且不知何故搞砸了,您可以执行fake 迁移。

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

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

              现在您可以轻松恢复迁移。

              PS:我被困了很长时间,执行虚假迁移然后恢复帮助我解决了问题。

              【讨论】:

              • 这个答案适用于 Django
              【解决方案8】:

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

              ...删除迁移,而不创建新迁移?

              TL;DR:您可以删除一些上次还原(混淆)的迁移,然后在修复模型后创建一个新迁移。您也可以使用其他方法通过migrate命令将其配置为不建表必须创建最后一个迁移,使其与当前模型匹配


              案例为什么有人不想为必须存在的模型创建表:

              A) 任何机器上的任何数据库中都不应该存在这样的表,并且没有条件

              • 何时:它是一个基础模型,仅为其他模型的模型继承而创建。
              • 解决方案: 设置class Meta: abstract = True

              B) 该表很少通过其他方式或以特殊方式手动创建。

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

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

              • 解决方案: 仅在特殊条件下将模型移动到添加到 INSTALLED_APPS 的新应用程序或使用条件 class Meta: managed = some_switch

              D)项目使用settings.DATABASES中的多个数据库

              • 解决方案: 使用方法allow_migrate 编写一个Database router,以区分应该创建表的数据库和不应该创建表的数据库。

              迁移是在 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

              【讨论】:

                【解决方案9】:

                这是我的解决方案,因为当您使用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 访问表。

                【讨论】:

                • 当使用 ForeignKeys 创建新模型时,进行多次迁移,然后意识到一切都是错误的,并向后重新启动 2-3 次迁移,使用新模型但有时模型名称相同或关系名称相同......这个解决方案显然是赢家。我收到了django.db.utils.ProgrammingError: relation "&lt;relation name&gt;" already exists 之类的错误消息,因此我输入了一个错误的migrate --fake,所以我尝试返回,然后得到psycopg2.ProgrammingError: relation "&lt;other &lt;relation name&gt;" does not exist 谢谢
                【解决方案10】:

                我在 1.9.1 中执行此操作(以删除创建的最后一个或最新的迁移):

                1. rm &lt;appname&gt;/migrations/&lt;migration #&gt;*

                  例子: rm myapp/migrations/0011*

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

                  delete from django_migrations where name like '0011%';

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

                【讨论】:

                • +1 虽然这可行,但您需要以这种方式保存作为最后的手段。此外,您必须记住编辑/删除有问题的迁移导致的列/表。
                • 好点 - 我在创建迁移时使用了它,但还没有运行“./manage.py migrate”
                【解决方案11】:

                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


                更新:编写此代码的更好方法是将上面的 sn-p 中的 lambda apps, schema_editor: None 替换为 migrations.RunPython.noop。这些在功能上都是一样的。 (感谢 cmets)

                【讨论】:

                • 从 Django 1.8 开始,您应该使用 RunPython.noop 而不是内联 lambda 或等效项:docs.djangoproject.com/en/1.8/ref/migration-operations/…
                • @SpoonMeiser 在示例的语法中,我认为它看起来像migrations.RunPython(forwards_func, migrations.RunPython.noop)。需要在功能上进行检查。有时应该将其添加为答案或对此进行编辑。
                【解决方案12】:

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

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

                【讨论】:

                • 在这种情况下要小心 - 您有义务验证 db 是否足够。
                • 我会非常小心地添加。你可以在 Postgres 中破坏很多东西,例如约束。
                猜你喜欢
                • 2019-09-02
                • 1970-01-01
                • 2011-05-22
                • 2015-05-06
                • 2015-03-25
                • 2017-01-07
                • 2011-12-03
                • 2019-12-31
                • 2018-02-22
                相关资源
                最近更新 更多