1. ホーム
  2. python

[解決済み] モデルとリレーションシップフィールドの名前を変更するためのDjangoマイグレーション戦略

2022-05-01 11:05:55

質問

既存の Django プロジェクトで、いくつかのモデルの名前を変更しようと思っています。そのモデルには、名前を変更したいモデルと外部キー関係を持つ他のモデルが多数存在します。この場合、複数のマイグレーションが必要であることは間違いないのですが、正確な手順がわかりません。

という Django アプリの中で、次のようなモデルから始めるとします。 myapp :

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

の名前を変更したい。 Foo というのも、この名前はあまり意味がなく、コードの混乱を引き起こしているからです。 Bar の方がより明確な名前になります。

Djangoの開発ドキュメントを読んだ限りでは、以下のような移行戦略を想定しています。

ステップ1

修正 models.py :

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()

注意 AnotherModel のフィールド名は foo は変更されませんが、リレーションが更新されて Bar というモデルを作成しました。私の推論は、一度に多くを変更すべきではなく、もしこのフィールド名を bar そのカラムのデータを失う危険性があるのです。

ステップ2

空のマイグレーションを作成します。

python manage.py makemigrations --empty myapp

ステップ3

を編集します。 Migration クラスを追加し、ステップ 2 で作成したマイグレーションファイルの RenameModel 演算を演算リストに追加します。

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

ステップ4

マイグレーションを適用します。

python manage.py migrate

ステップ5

の関連フィールド名を編集します。 models.py :

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

ステップ6

別の空のマイグレーションを作成します。

python manage.py makemigrations --empty myapp

ステップ7

を編集します。 Migration クラスを追加し、ステップ 6 で作成したマイグレーションファイルの RenameField の操作に関連するフィールド名を操作リストに追加します。

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

ステップ8

2回目のマイグレーションを適用します。

python manage.py migrate


新しい変数名を反映させるために残りのコード(ビュー、フォームなど)を更新することは別として、新しいマイグレーション機能は基本的にこのように動作するのでしょうか?

また、手順が多いように思います。何らかの方法で移行作業を凝縮できないでしょうか?

ありがとうございます。

解決方法は?

で、やってみると、どうやらStep3~7を凝縮することができるようです。

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

admin.pyや古いマイグレーションファイル(!)など、インポートされている名前を更新しないと、エラーが発生する可能性があります。

更新 : として シーザロ が言及しているように、新しいバージョンの Django は通常、モデルがリネームされたかどうかを検出し、尋ねることができます。そこで manage.py makemigrations をまず確認し、その後マイグレーションファイルを確認してください。