django 迁移 - 具有多个开发分支的工作流
问题描述
我很好奇其他 django 开发人员如何通过迁移管理多个代码分支(例如在 git 中).
I'm curious how other django developers manage multiple code branches (in git for instance) with migrations.
我的问题如下:- 我们在 git 中有多个特性分支,其中一些带有 django 迁移(其中一些会更改字段,或者完全删除它们)- 当我切换分支(使用 git checkout some_other_branch
)时,数据库并不总是反映新代码,所以我遇到了随机"错误,其中 db 表列不再存在,等等..
My problem is as follows:
- we have multiple feature branches in git, some of them with django migrations (some of them altering fields, or removing them altogether)
- when I switch branches (with git checkout some_other_branch
) the database does not reflect always the new code, so I run into "random" errors, where a db table column does not exist anymore, etc...
现在,我只是删除数据库并重新创建它,但这意味着我必须重新创建一堆虚拟数据才能重新开始工作.我可以使用固定装置,但它需要跟踪哪些数据流向何处,这有点麻烦.
Right now, I simply drop the db and recreate it, but it means I have to recreate a bunch of dummy data to restart work. I can use fixtures, but it requires keeping track of what data goes where, it's a bit of a hassle.
是否有处理这个用例的好/干净的方法?我在想 post-checkout
git hook 脚本可以运行必要的迁移,但我什至不知道迁移回滚是否可能.
Is there a good/clean way of dealing with this use-case? I'm thinking a post-checkout
git hook script could run the necessary migrations, but I don't even know if migration rollbacks are at all possible.
解决方案
迁移回滚是可能的,通常由 django 自动处理.
Migrations rollback are possible and usually handled automatically by django.
考虑以下模型:
class MyModel(models.Model):
pass
如果您运行 python manage.py makemigrations myapp
,它将生成初始迁移脚本.然后,您可以运行 python manage.py migrate myapp 0001
以应用此初始迁移.
If you run python manage.py makemigrations myapp
, it will generate the initial migration script.
You can then run python manage.py migrate myapp 0001
to apply this initial migration.
如果之后您向模型添加一个字段:
If after that you add a field to your model:
class MyModel(models.Model):
my_field = models.CharField()
然后重新生成一个新的迁移,并应用它,你仍然可以回到初始状态.赶紧跑python manage.py migrate myapp 0001
并且 ORM 将向后移动,删除新字段.
Then regenerate a new migration, and apply it, you can still go back to the initial state. Just run
python manage.py migrate myapp 0001
and the ORM will go backward, removing the new field.
处理数据迁移时更棘手,因为您必须编写前向和后向代码.考虑通过 python manage.py makemigrations myapp --empty
创建的空迁移,你最终会得到类似的东西:
It's more tricky when you deal with data migrations, because you have to write the forward and backward code.
Considering an empty migration created via python manage.py makemigrations myapp --empty
,
you'll end up with something like:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
def forward(apps, schema_editor):
# load some data
MyModel = apps.get_model('myapp', 'MyModel')
while condition:
instance = MyModel()
instance.save()
def backward(apps, schema_editor):
# delete previously loaded data
MyModel = apps.get_model('myapp', 'MyModel')
while condition:
instance = MyModel.objects.get(myargs)
instance.delete()
class Migration(migrations.Migration):
dependencies = [
('myapp', '0003_auto_20150918_1153'),
]
operations = [
migrations.RunPython(forward, backward),
]
对于纯数据加载迁移,您通常不需要向后迁移.但是,当您更改架构并更新现有行时,
(例如将列中的所有值转换为 slug),您通常必须编写后退步骤.
For pure data-loading migrations, you usually don't need the backward migration.
But when you alter the schema and update existing rows,
(like converting all values in a column to slug), you'll generally have to write the backward step.
在我们的团队中,我们尽量避免同时处理相同的模型以避免冲突.如果不可能,并且创建了两个具有相同编号(例如 0002)的迁移,您仍然可以重命名其中一个以更改它们将被应用的顺序(还记得更新迁移类上的 dependencies
属性到您的新订单).
In our team, we try to avoid working on the same models at the same time to avoid collision.
If it is not possible, and two migration with the same number (e.g 0002) are created,
you can still rename one of them to change the order in will they will be applied (also remember to update
the dependencies
attribute on the migration class to your new order).
如果您最终在不同的功能中同时处理相同的模型字段,您仍然会遇到麻烦,但这可能意味着这些功能是相关的并且应该处理在一个分支中.
If you end up working on the same model fields at the same time in different features, you'll still be in trouble, but it may means these features are related and should be handled together in a single branch.
对于 git-hooks 部分,可能会写一些东西,假设你在分支 mybranch
并想查看另一个功能分支 myfeature
:
For the git-hooks part, it's probably possible to write something, Assuming your are on branch mybranch
and want to check out another feature branch myfeature
:
- 就在切换之前,您将当前应用的迁移列表转储到一个临时文件
mybranch_database_state.txt
- 然后,您应用
myfeature
分支迁移(如果有) - 然后,在检查
mybranch
时,您重新应用之前的数据库状态通过查看转储文件.
- Just before switching, you dump the list of currently applied migrations into
a temporary file
mybranch_database_state.txt
- Then, you apply
myfeature
branch migrations, if any - Then, when checking back
mybranch
, you reapply your previous database state by looking to the dump file.
但是,这对我来说似乎有点 hackish,并且可能真的很难正确处理所有场景:变基、合并、挑选等.
However, it seems a bit hackish to me, and it would probably be really difficult to handle properly all scenarios: rebasing, merging, cherry-picking, etc.
对我来说,在发生迁移冲突时处理它们似乎更容易.
Handling the migrations conflicts when they occurs seems easier to me.
相关文章