带有转储数据和迁移的 Django 备份策略
Django backup strategy with dumpdata and migrations
如 this question, I set up a dumpdata
-based backup system for my database. The setup is akin to running a cron script that calls dumpdata
and moves the backup to a remote server, with the aim of simply using loaddata
to recover the database. However, I'm not sure this plays well with migrations. loaddata
now has an ignorenonexistent
开关处理已删除的 models/fields,但它无法解决使用一次性默认值添加列或应用 RunPython
代码的情况。
在我看来,有两个子问题需要解决:
- 用每个应用程序的当前版本标记每个
dumpdata
输出文件
- 将fixtures拼接到迁移路径中
我对如何在不引入大量开销的情况下解决第一个问题感到困惑。为每个包含 {app_name: migration_number}
映射的备份保存一个额外文件是否足够?
第一个问题解决后第二个问题我觉得比较容易,因为过程大致是:
- 创建新数据库
- 运行 迁移到每个应用程序的适当点
- 使用给定的夹具文件调用
loaddata
- 运行 其余迁移
this question 中有一些代码(链接自错误报告)我认为可以针对此目的进行调整。
由于这些是数据库的 regular/large 快照,我不想将它们保留为数据迁移,使迁移目录变得混乱。
我正在采取以下步骤在我的项目的任何实例之间备份、恢复或传输我的 postgresql 数据库:
我们的想法是保持尽可能少的迁移,就好像 manage.py makemigrations
是第一次在空数据库上 运行 一样。
假设我们的开发环境有一个可用的数据库。此数据库是生产数据库 的当前副本,不应对任何更改开放 。我们添加了模型、更改了属性等,这些操作产生了额外的迁移。
现在数据库已准备好迁移到生产环境,如前所述,生产环境未对 public 开放,因此不会以任何方式更改。为了实现这一点:
- 我在开发环境中执行正常程序。
- 我把项目拷贝到生产环境中
- 我在生产环境执行正常程序
我们对开发环境进行了更改。生产数据库中不应发生任何更改,因为 它们将被覆盖。
正常程序
首先,我有一个项目目录的备份(其中包括一个 requirements.txt 文件),一个数据库的备份,当然还有 git
是我的一个朋友。
我做了一个 dumpdata
备份以备不时之需。不过,dumpdata
有些严重 limitations regarding content types, permissions or other cases where a natural foreignkey应该用:
./manage.py dumpdata --exclude auth.permission --exclude contenttypes --exclude admin.LogEntry --exclude sessions --indent 2 > db.json
我取一个pg_dump
备份使用:
pg_dump -U $user -Fc $database --exclude-table=django_migrations > path/to/backup-dir/db.dump
只有当我想将现有的迁移合并为一个时,我才会从每个应用程序中删除所有迁移。
在我的例子中,migrations
文件夹是一个符号链接,所以我使用以下脚本:
#!/bin/bash
for dir in $(find -L -name "migrations")
do
rm -Rf $dir/*
done
我删除并重新创建数据库:
例如,bash 脚本可以包含以下命令:
su -l postgres -c "PGPASSWORD=$password psql -c 'drop database $database ;'"
su -l postgres -c "createdb --owner $username $database"
su -l postgres -c "PGPASSWORD=$password psql $database -U $username -c 'CREATE EXTENSION $extension ;'"
我从转储中恢复数据库:
pg_restore -Fc -U $username -d $database path/to/backup-dir/db.dump
如果在步骤 3 中删除了迁移,我将按以下方式重新创建它们:
./manage.py makemigrations <app1> <app2> ... <appn>
... 通过使用以下脚本:
#!/bin/bash
apps=()
for app in $(find ./ -maxdepth 1 -type d ! -path "./<project-folder> ! -path "./.*" ! -path "./")
do
apps+=(${app#??})
done
all_apps=$(printf "%s " "${apps[@]}")
./manage.py makemigrations $all_apps
我使用假迁移进行迁移:
./manage.py migrate --fake
如果出现完全错误并且一切都是 ***,(这确实可能发生),我可以使用备份将一切恢复到以前的工作状态。如果我想使用第一步中的 db.json
文件,它是这样的:
当pg_dump或pg_restore失败时
我执行以下步骤:
- 3(删除迁移)
- 4(删除并重新创建数据库)
- 6(进行迁移)
然后:
应用迁移:
./manage.py migrate
从 db.json:
加载数据
./manage.py loaddata path/to/db.json
然后我试着找出我之前的努力没有成功的原因。
成功执行这些步骤后,我将项目复制到服务器并对该框执行相同的操作。
这样,我总是保持最少的迁移次数,并且我能够对共享同一项目的任何框使用 pg_dump
和 pg_restore
。
如 this question, I set up a dumpdata
-based backup system for my database. The setup is akin to running a cron script that calls dumpdata
and moves the backup to a remote server, with the aim of simply using loaddata
to recover the database. However, I'm not sure this plays well with migrations. loaddata
now has an ignorenonexistent
开关处理已删除的 models/fields,但它无法解决使用一次性默认值添加列或应用 RunPython
代码的情况。
在我看来,有两个子问题需要解决:
- 用每个应用程序的当前版本标记每个
dumpdata
输出文件 - 将fixtures拼接到迁移路径中
我对如何在不引入大量开销的情况下解决第一个问题感到困惑。为每个包含 {app_name: migration_number}
映射的备份保存一个额外文件是否足够?
第一个问题解决后第二个问题我觉得比较容易,因为过程大致是:
- 创建新数据库
- 运行 迁移到每个应用程序的适当点
- 使用给定的夹具文件调用
loaddata
- 运行 其余迁移
this question 中有一些代码(链接自错误报告)我认为可以针对此目的进行调整。
由于这些是数据库的 regular/large 快照,我不想将它们保留为数据迁移,使迁移目录变得混乱。
我正在采取以下步骤在我的项目的任何实例之间备份、恢复或传输我的 postgresql 数据库:
我们的想法是保持尽可能少的迁移,就好像 manage.py makemigrations
是第一次在空数据库上 运行 一样。
假设我们的开发环境有一个可用的数据库。此数据库是生产数据库 的当前副本,不应对任何更改开放 。我们添加了模型、更改了属性等,这些操作产生了额外的迁移。
现在数据库已准备好迁移到生产环境,如前所述,生产环境未对 public 开放,因此不会以任何方式更改。为了实现这一点:
- 我在开发环境中执行正常程序。
- 我把项目拷贝到生产环境中
- 我在生产环境执行正常程序
我们对开发环境进行了更改。生产数据库中不应发生任何更改,因为 它们将被覆盖。
正常程序
首先,我有一个项目目录的备份(其中包括一个 requirements.txt 文件),一个数据库的备份,当然还有 git
是我的一个朋友。
我做了一个
dumpdata
备份以备不时之需。不过,dumpdata
有些严重 limitations regarding content types, permissions or other cases where a natural foreignkey应该用:./manage.py dumpdata --exclude auth.permission --exclude contenttypes --exclude admin.LogEntry --exclude sessions --indent 2 > db.json
我取一个
pg_dump
备份使用:pg_dump -U $user -Fc $database --exclude-table=django_migrations > path/to/backup-dir/db.dump
只有当我想将现有的迁移合并为一个时,我才会从每个应用程序中删除所有迁移。
在我的例子中,
migrations
文件夹是一个符号链接,所以我使用以下脚本:#!/bin/bash for dir in $(find -L -name "migrations") do rm -Rf $dir/* done
我删除并重新创建数据库:
例如,bash 脚本可以包含以下命令:
su -l postgres -c "PGPASSWORD=$password psql -c 'drop database $database ;'" su -l postgres -c "createdb --owner $username $database" su -l postgres -c "PGPASSWORD=$password psql $database -U $username -c 'CREATE EXTENSION $extension ;'"
我从转储中恢复数据库:
pg_restore -Fc -U $username -d $database path/to/backup-dir/db.dump
如果在步骤 3 中删除了迁移,我将按以下方式重新创建它们:
./manage.py makemigrations <app1> <app2> ... <appn>
... 通过使用以下脚本:
#!/bin/bash apps=() for app in $(find ./ -maxdepth 1 -type d ! -path "./<project-folder> ! -path "./.*" ! -path "./") do apps+=(${app#??}) done all_apps=$(printf "%s " "${apps[@]}") ./manage.py makemigrations $all_apps
我使用假迁移进行迁移:
./manage.py migrate --fake
如果出现完全错误并且一切都是 ***,(这确实可能发生),我可以使用备份将一切恢复到以前的工作状态。如果我想使用第一步中的 db.json
文件,它是这样的:
当pg_dump或pg_restore失败时
我执行以下步骤:
- 3(删除迁移)
- 4(删除并重新创建数据库)
- 6(进行迁移)
然后:
应用迁移:
./manage.py migrate
从 db.json:
加载数据./manage.py loaddata path/to/db.json
然后我试着找出我之前的努力没有成功的原因。
成功执行这些步骤后,我将项目复制到服务器并对该框执行相同的操作。
这样,我总是保持最少的迁移次数,并且我能够对共享同一项目的任何框使用 pg_dump
和 pg_restore
。