我正在采取以下步骤在我的项目的任何实例之间备份、恢复或传输我的 postgresql 数据库:
这个想法是保持尽可能少的迁移,就好像manage.py makemigrations
第一次在空数据库上运行一样。
假设我们的开发环境有一个工作数据库。此数据库是生产数据库的当前副本,不应对任何更改开放。我们添加了模型、更改了属性等,这些操作产生了额外的迁移。
现在数据库已准备好迁移到生产环境,如前所述,该数据库不向公众开放,因此不会以任何方式进行更改。为了实现这一点:
- 我在开发环境中执行正常程序。
- 我将项目复制到生产环境。
- 我在生产环境中执行正常程序
我们在开发环境中进行更改。生产数据库中不应发生任何更改,因为它们将被覆盖。
正常程序
首先,我有一个项目目录的备份(其中包括一个 requirements.txt 文件),一个数据库的备份——当然——git
是我的一个朋友。
我会dumpdata
备份以备不时之需。但是,对于内容类型、权限或应使用自然外键的其他情况,dumpdata
有一些严重的 限制:
./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(迁移)
接着:
然后我试图找出为什么我之前的努力没有成功。
成功执行这些步骤后,我将项目复制到服务器并对该框执行相同的步骤。
这样,我总是保持最少的迁移次数,并且我能够使用pg_dump
和pg_restore
共享同一项目的任何盒子。