web-dev-qa-db-ja.com

django移行-複数の開発ブランチを持つワークフロー

他のDjango開発者が移行で複数のコードブランチ(たとえばgit)を管理する方法に興味があります。

私の問題は次のとおりです:-gitに複数の機能ブランチがあり、その一部はDjango移行(一部はフィールドを変更するか、完全に削除する)で)-ブランチを切り替えると(git checkout some_other_branch)データベースが常に新しいコードを反映するわけではないため、「ランダム」エラーが発生し、データベーステーブルの列がもう存在しない、など...

現時点では、dbを削除して再作成するだけですが、作業を再開するには一連のダミーデータを再作成する必要があります。フィクスチャを使用できますが、どのデータがどこに行くのかを追跡する必要があります。これは少し面倒です。

このユースケースに対処するための良い/クリーンな方法はありますか? post-checkout gitフックスクリプトが必要な移行を実行できると思いますが、移行のロールバックが可能かどうかさえわかりません。

35
Laurent S

マイグレーションのロールバックは可能で、通常は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),
    ]

純粋なデータ読み込み移行の場合、通常、逆方向の移行は必要ありません。しかし、スキーマを変更して既存の行を更新すると、
(列のすべての値をスラッグに変換するように)、通常は逆方向のステップを記述する必要があります。

私たちのチームでは、衝突を避けるために、同じモデルで同時に作業することを避けようとしています。それが不可能で、同じ番号(0002など)の2つの移行が作成された場合でも、それらの1つを名前変更して、適用される順序を変更できます(dependencies属性を更新することも忘れないでください)新しい注文への移行クラス)。

異なる機能で同時に同じモデルフィールドで作業することになった場合でも問題が発生しますが、これらの機能は関連しており、1つのブランチで一緒に処理する必要があることを意味します。

Git-hooksの部分については、おそらく何かを書くことが可能です。あなたがブランチmybranchにいて、別の機能ブランチmyfeatureをチェックアウトしたいとします:

  1. 切り替える直前に、現在適用されている移行のリストを一時ファイルにダンプしますmybranch_database_state.txt
  2. 次に、myfeatureブランチの移行があれば、それを適用します
  3. 次に、mybranchをチェックバックするときに、ダンプファイルを調べて、以前のデータベースの状態を再適用します。

しかし、私には少しハックに思え、リベース、マージ、チェリーピッキングなどのすべてのシナリオを適切に処理することはおそらく本当に難しいでしょう。

移行の競合が発生したときにそれを処理することは、私には簡単に思えます。

19
Eliot Berriot

これには良い解決策はありませんが、痛みを感じます。

チェックアウト後のフックは遅すぎます。ブランチAでブランチBをチェックアウトし、BのマイグレーションがAより少ない場合、ロールバック情報はAのみにあり、実行する必要がありますbeforeチェックアウト。

バグの原因を特定しようとする複数のコミット間をジャンプするときに、この問題に遭遇しました。私たちのデータベース(開発段階でも)は巨大なので、削除して再作成することは現実的ではありません。

私はgit-checkoutのラッパーを想像しています:

  1. 各INSTALLED_APPSの最新の移行に注意してください
  2. リクエストされたブランチを調べて、そこに最新のマイグレーションを記録します
  3. #1での移行が#2での移行よりも進んでいるアプリごとに、#2で最も高い移行に戻します。
  4. 新しいブランチをチェックしてください
  5. #2の移行が#1を上回っていた各アプリについて、前に移行

プログラミングの簡単な問題!

7
Paul Bissex