django 迁移 - 具有多个开发分支的工作流

django migrations - workflow with multiple dev branches

我很好奇其他 Django 开发人员如何通过迁移管理多个代码分支(例如 git)。

我的问题如下: - 我们在 git 中有多个功能分支,其中一些带有 django 迁移(其中一些更改字段,或完全删除它们) - 当我切换分支(使用 git checkout some_other_branch)时,数据库并不总是反映新代码,所以我 运行 进入 "random" 错误,其中 db table 列不存在等等...

现在,我只是删除数据库并重新创建它,但这意味着我必须重新创建一堆虚拟数据才能重新开始工作。我可以使用固定装置,但它需要跟踪哪些数据去了哪里,这有点麻烦。

是否有 good/clean 处理此用例的方法?我在想 post-checkout git 挂钩脚本可以 运行 必要的迁移,但我什至不知道迁移回滚是否完全可能。

迁移回滚是可能的,通常由 django 自动处理。

考虑以下模型:

class MyModel(models.Model):
    pass
    

如果你运行python manage.py makemigrations myapp,它会生成初始迁移脚本。 然后,您可以 运行 python manage.py migrate myapp 0001 应用此初始迁移。

如果之后您向模型中添加一个字段:

class MyModel(models.Model):    
    my_field = models.CharField()
    

然后重新生成一个新的迁移,并应用它,你仍然可以回到初始状态。只是 运行 python manage.py migrate myapp 0001 并且 ORM 将倒退,删除 新字段。

处​​理数据迁移时比较棘手,因为你必须编写前向和后向代码。 考虑通过 python manage.py makemigrations myapp --empty 创建的空迁移, 你最终会得到这样的结果:

# -*- 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),您通常必须编写向后步骤。

在我们的团队中,我们尽量避免同时处理相同的模型以避免冲突。 如果不可能,并且创建了两个具有相同编号(例如 0002)的迁移, 您仍然可以重命名其中之一以更改它们的应用顺序(还记得更新 迁移 class 到您的新订单的 dependencies 属性)。

如果您最终在不同的功能中同时处理相同的模型字段, 你仍然会有麻烦,但这可能意味着这些功能是相关的,应该处理 一起在一个分支中。

对于 git-hooks 部分,可能会写一些东西,假设你在分支 mybranch 并想查看另一个功能分支 myfeature:

  1. 就在切换之前,您将当前应用的迁移列表转储到 临时文件 mybranch_database_state.txt
  2. 然后,您应用 myfeature 分支迁移,如果有的话
  3. 然后,当回头检查 mybranch 时,您重新应用以前的数据库状态 通过查看转储文件。

然而,这对我来说似乎有点 hackish,并且可能真的很难正确处理所有场景: 变基、合并、挑选樱桃等

在发生迁移冲突时处理它们对我来说似乎更容易。

我对此没有很好的解决方案,但我感到很痛苦。

一个post-checkout hook 来不及了。如果你在A分支上,check out分支B,B的迁移比A少,回滚信息只在A,需要运行 before checkout。

我在多次提交之间跳转试图找到错误的根源时遇到了这个问题。我们的数据库(即使在开发 trim)是巨大的,所以删除和重新创建是不切实际的。

我正在为 git 设计一个包装器-结帐:

  1. 记录每个 INSTALLED_APPS
  2. 的最新迁移
  3. 查看请求的分支并记录那里的最新迁移
  4. 对于#1 中的迁移比#2 中的迁移更早的每个应用程序,迁移回#2 中的最高迁移
  5. 查看新分支
  6. 对于#2 中的迁移早于#1 的每个应用,向前迁移

一个简单的编程问题!

对于简单的更改,我依赖于迁移回滚,正如 所讨论的那样。

但是,如果我知道一个功能分支将涉及高度侵入性的数据库更改,或者如果它将涉及大量数据迁移,我希望尽快创建本地(或远程开发)数据库的克隆当我开始新分支时。这可能并不总是很方便,但特别是对于使用 sqlite 的本地开发,只需复制一个文件(不受源代码控制)。

新分支上的第一次提交然后更新我的 Django settings (local/dev) 以使用克隆的数据库。这样,当我切换分支时,会自动选择正确的数据库。无需担心回滚架构更改、丢失数据等。没有复杂的东西。

功能分支完全合并后,可以删除克隆的数据库。