django migrations -具有多个开发分支的工作流程

92dk7w1h  于 2022-11-18  发布在  Go
关注(0)|答案(4)|浏览(143)

我很好奇其他的django开发者是如何通过迁移来管理多个代码分支的(比如在git中)。
我的问题如下:- 我们在git中有多个特性分支,其中一些带有django迁移(其中一些修改字段,或者完全删除它们)-当我切换分支(使用git checkout some_other_branch)时,数据库并不总是反映新代码,所以我遇到了“随机”错误,其中一个db表列不再存在,等等...
现在,我只是删除数据库并重新创建它,但这意味着我必须重新创建一堆虚拟数据来重新开始工作。我可以使用fixture,但它需要跟踪哪些数据去了哪里,这有点麻烦。
有没有一个好的/干净的方法来处理这个用例?我想一个post-checkout git hook脚本可以运行必要的迁移,但是我甚至不知道迁移回滚是否是可能的。

3zwjbxry

3zwjbxry1#

迁移回滚是可能的,通常由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)的迁移,您仍然可以重命名其中一个,以更改它们将被应用的顺序(还记得将迁移类上的dependencies属性更新为您的新顺序)。
如果您最终在不同的特性中同时处理相同的模型字段,您仍然会遇到麻烦,但这可能意味着这些特性是相关的,应该在单个分支中一起处理。
对于git-hooks部分,可以写一些东西,假设你在分支mybranch上,想查看另一个分支myfeature的特性:
1.就在切换之前,将当前应用的迁移列表转储到临时文件mybranch_database_state.txt
1.然后,应用myfeature分支迁移(如果有)
1.然后,在签回mybranch时,通过查看转储文件重新应用以前的数据库状态。
然而,对我来说,这似乎有点笨拙,而且很可能很难正确处理所有场景:重订基准、合并、摘樱桃等
对我来说,处理迁移冲突似乎更容易。

2j4z5cfb

2j4z5cfb2#

我没有一个很好的解决办法,但我感到痛苦。
如果您在分支A上 checkout 分支B,而B的迁移比A少,则回滚信息只在A中,需要在 checkout * 之前 * 运行。
当我在几个提交之间跳转试图定位bug的起源时遇到了这个问题。我们的数据库(即使在开发调整中)是巨大的,所以删除和重新创建是不现实的。
我在想象一个git-checkout的 Package 器:
1.记录每个INSTALLED_APPS的最新迁移
1.在请求的分支中查找并记下最新的迁移
1.对于#1中的迁移比#2中的迁移更早的每个应用程序,迁移回#2中的最高迁移
1.查看新分支
1.对于#2中的迁移早于#1的每个应用程序,向前迁移
一个简单的编程问题!

nafvub8i

nafvub8i3#

对于简单的更改,我依赖于迁移回滚,如Agate所述。
然而,如果我知道一个特性分支将涉及到高度侵入性的数据库更改,或者如果它将涉及到大量的数据迁移,我喜欢在启动新分支时立即创建一个本地(或远程开发)数据库的克隆。这可能并不总是方便的,但特别是对于使用sqlite的本地开发来说,它只是复制一个文件(不受源代码控制)的问题。
在新分支上的第一次提交会更新我的Django设置(local/dev)以使用克隆的数据库。这样,当我切换分支时,正确的数据库会被自动选择。无需担心回滚模式更改,丢失数据等。没有复杂的东西。
完全合并功能分支后,可以删除克隆的数据库。

monwx1rj

monwx1rj4#

到目前为止,我已经找到了两个Github项目(django-south-compassdjango_nomad),它们试图解决开发分支之间的迁移问题,并且有一些关于堆栈溢出的答案。
引用article on Medium,大多数解决方案可归结为以下概念之一:
1.删除所有表并从头开始在目标分支中重新应用迁移。从头开始创建表时,所有数据都将丢失,并且还需要重新创建。这可以通过fixture和数据迁移来处理,但反过来,管理它们将成为一场噩梦,更不用说这将花费一些时间(...)
1.为每个分支建立一个单独的数据库,并在每次使用sed之类的工具切换分支时,使用目标分支的设置来更改设置文件。这可以通过post_checkout钩子来完成。为每个分支维护一个大型数据库会占用大量存储空间。此外, checkout 单个提交ID可能会产生同样的错误。
1.查找源分支和目标分支之间的迁移差异,并应用这些差异。我们可以使用post_checkout脚本来执行此操作,但有一个小问题。This post详细解释了此问题。总结一下此问题,在 checkout 目标分支中的所有文件后运行post_checkout,如果目标分支不包含源分支中的所有迁移,那么当我们运行python manage.py migrate app1时Django将无法找到应用反向迁移所需的缺失的迁移。我们必须临时 checkout 源分支中的迁移文件,运行python manage.py migrate并 checkout 目标分支中的迁移文件。django-south-compass的功能非常相似,但仅适用于python 2.6以上的版本。
1.使用管理命令(使用python git模块),找出源分支和目标分支的合并基础与源分支之间的所有迁移操作差异,并通知用户这些更改。如果这些更改不影响分支更改的原因,用户可以继续更改分支。否则,使用另一个管理命令,取消应用所有迁移,直到合并基础,switch分支,并在目标分支中应用迁移。会有少量的数据丢失,如果两个分支没有太大的分歧,这是可以管理的。django_nomad会做一些工作。
1.跟踪文件中已应用和未应用的迁移,并在切换分支时使用此数据填充表。

相关问题