HOWTO · Django
回滚 Django 中的最后一次数据库迁移
本文为你提供了有关如何在 Django 中恢复到上次数据库迁移的讨论。
本页内容
要撤销最近一次已应用的 Django 迁移,请运行 python manage.py migrate <app_label> <migration_name>,并选择应保持为已应用状态的迁移;通常是要撤销的迁移之前那一个。Django 会撤销指定应用中位于该目标之后的迁移。先使用 showmigrations 查看应用当前的迁移状态。回滚前请备份重要数据:撤销架构操作可能会丢弃数据,而且有些操作根本无法撤销。
回滚到指定迁移
使用 python manage.py showmigrations <app_label> 列出某个应用的迁移。已应用的迁移标记为 [X],尚未应用的迁移标记为 [ ]。应用标签是 Django 迁移命令中使用的应用名称;迁移名称则是文件名中不含 .py 的部分。
例如,假设 blog 有 0001_initial、0002_add_author 和 0003_remove_legacy_field 三个迁移,而且它们都已应用。若只要撤销 0003_remove_legacy_field,目标应设为 0002_add_author:python manage.py migrate blog 0002_add_author。目标表示操作后要保留的最终迁移状态,而不是要撤销的迁移。Django 会撤销 blog 中的 0003 以及之后所有已应用的迁移。像 0002 这样的数字前缀可以用来指定目标;写出完整名称则更容易确认选择无误。
请在能让 manage.py 加载正确设置并连接到目标数据库的项目环境中运行命令。执行前请确认目标应用和数据库;尤其是在配置了多个环境时,更要仔细核对。
运行以下 Python 代码片段,为一个应用和目标迁移生成命令:
本节中的代码以及显示的标签或输出仍为英文。
app_label = "blog"
target = "0002_add_author"
print(f"python manage.py migrate {app_label} {target}")
python manage.py migrate blog 0002_add_author
该代码片段只负责拼出命令;下方代码及其输出中的命令保持英文,这是 Django 命令本身的写法。请在 Django 项目中运行生成的命令,才能更改数据库状态。
回滚某个应用的全部迁移
若要撤销某个应用的所有已应用迁移,请使用 python manage.py migrate <app_label> zero,例如 python manage.py migrate blog zero。这里的 zero 表示该应用尚未应用任何迁移时的目标状态。Django 会按照迁移历史的逆序撤销该应用的迁移。这并不只是“撤销最近一次迁移”,还可能删除数据表或列及其中的数据。使用这个目标前,请检查该应用的迁移列表并备份数据库。
若要撤销多个迁移但保留一部分,请指定一个更早的迁移作为目标。Django 会从当前已应用状态向回处理,直到到达该目标。其他应用的迁移不会仅仅因为它们在整个项目历史中的位置较晚就被选中,不过迁移依赖关系可能会影响执行计划。对生产环境进行更改前,请先查看 Django 计划执行的操作。
了解可逆性与数据丢失
如果迁移定义了反向操作,或者 Django 能够推断出反向操作,Django 就可以撤销该操作。有些操作无法还原,例如使用没有反向函数的自定义 Python 操作删除数据。尝试撤销这类迁移时会引发 IrreversibleError。请检查迁移中的操作以及完整错误信息,找出缺少反向路径的步骤;不要以为恢复较早版本的迁移文件就能撤销它对数据库造成的影响。
即使架构更改可以逆转,也仍可能丢失数据。例如,撤销删除字段的操作,无法恢复删除该字段时已丢弃的值。回滚前,请备份数据库,确认是否需要暂停应用写入,并考虑向前修复是否更安全。在生产环境中更改实时数据库之前,请先用近期备份演练操作流程,并确认恢复方案可行。
Git 管理迁移源文件,而 migrate 更改数据库状态。检出或还原 Git 提交本身不会回滚数据库。单独恢复迁移文件也可能造成代码与数据库记录的迁移历史不一致,因此数据库操作应使用 Django 迁移命令;如需恢复代码,应另外协调处理。
验证数据库状态
命令执行完毕后,再次运行 python manage.py showmigrations <app_label>。确认目标迁移及更早的迁移显示 [X],已撤销的迁移显示 [ ]。这反映的是 Django 记录的迁移状态;它不能验证应用层面的所有数据预期,也不能证明架构和数据都处于健康状态。请检查受影响应用的行为;必要时检查数据库或运行项目专用的检查。
如果这些标记与预期目标不符,请先停止,不要继续发出另一次回滚命令。确认当前连接的是目标数据库,检查命令输出和迁移依赖关系,然后根据实际记录的状态决定下一步迁移操作。