Django-Southを使用してモデルフィールドの名前を変更する方法


209

モデルの特定のフィールドの名前を変更したいと思います。

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

に変更する必要があります:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

サウスを使用してこれを行う最も簡単な方法は何ですか?


7
モデルフィールドではなくモデルの名前を変更するには、stackoverflow.com / questions / 2862979 /…も参照してください。
メカニカルカタツムリ

回答:


230

db.rename_column関数を使用できます。

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

の最初の引数db.rename_columnはテーブル名なので、Djangoがテーブル名を作成する方法を覚えておくことが重要です。

Djangoは、モデルクラスの名前とそれを含むアプリからデータベーステーブルの名前を自動的に取得します。モデルのデータベーステーブル名は、モデルの「アプリラベル」(manage.py startappで使用した名前)をモデルのクラス名とアンダースコアで結合して作成されます。

あなたはマルチ文言持っている場合、そのようなのProjectItem、テーブル名とキャメルケースモデル名は、になりますapp_projectitem(つまり、アンダースコアが間に挿入されることはありませんprojectし、item彼らはキャメルケースであっても)。


2
これはname \ full_nameでは機能しますが、リレーションフィールドでは機能しません。
ジョナサン

23
重要な注意:これを使用する場合は、「app_foo」がデータベーステーブル名であることを確認してください。たとえば、「mainapp_profile」、「name」はデータベースの古い列名です(モデルフィールド名ではありません)。たとえば、「user_id」と「full_name」は、列に付ける新しい名前になります(ここでも、フィールド名ではなくデータベース列です)。したがって:db.rename_column( 'mainapp_profile'、 'user_id'、 'new_user_id')また、外部キーを処理する場合は、名前を変更するときに "_id"の部分を含める必要があります。
Gezim

3
このdb.rename_columnを手動で行う場合は、後でクリーンアップを行うために偽のスキーマ移行を行う必要がある場合があります。それは最初に列の名前を変更して変更を移行します。次に、モデルを修正して(名前を更新します)、次に./manage.py schemamigration app --auto && ./manage.py migrate app --fakeを実行します。
ジンボブ博士、2011年

24
また、空の移行を作成し、それにコードを配置する./manage.py schemamigration MY_APP renaming_column_x --emptyを使用することができます
イリアン・イリーブ

11
--emptyはあまり役に立ちませんが、代わりに--autoを使用して、作成された移行を変更します。この方法では、models.pyの次の移行のためにフィールドが削除されたとは主張しません。
yasc 2013年

39

これが私がすることです:

  1. モデルで列名を変更します(この例ではmyapp/models.py
  2. 走る ./manage.py schemamigration myapp renaming_column_x --auto

メモrenaming_column_xは好きなものにすることができます。これは、移行ファイルに説明的な名前を付けるための方法にすぎません。

これによりmyapp/migrations/000x_renaming_column_x.py、古い列を削除して新しい列を追加するというファイルが生成されます。

このファイルのコードを変更して、移行動作を単純な名前変更に変更します。

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')

コマンドの列の名前は何ですか?xまたはcolumn_x
andilabs 2014

あなたが参照しているコマンドの一部は、単にマイグレーションに名前を付けるために使用されています。列名は、編集時に移行ファイルで指定する必要があります。
donturner 14

2
--auto最初にマイグレーションを作成することは、すばらしいヒントです。これは、移行にforwardsbackwardsメソッドしかなく、凍結されたmodelオブジェクトが含まれていない場合に発生する、South ORM Freezerの問題を回避します。
mwcz 2014年

南部の質問「このフィールドを削除するため、デフォルトを指定する必要があります」にどのように答えますか?
ブライス

3
このメソッドの1つの問題は、列に関連付けられている制約のdb.rename_column名前を変更しないことです。移行は引き続き機能しますが、古い列名にちなんだ名前の制約があります。一意性制約のある列があり、このメソッドを使用して名前を変更しました。一意性制約がまだ存在し、エラーが発生することをテストしましたが、制約自体の名前には古い列名がまだ使用されていました。おそらく明示的であり、それを行ったはずですが、私はsjhのソリューションを採用することにしました。db.delete_uniquedb.create_unique
Louis

15

db.rename列については知りませんでしたが、便利なようですが、以前は新しい列を1つのスキーマ移行として追加し、次にデータ移行を作成して値を新しいフィールドに移動し、2番目のスキーマ移行で古い列を削除しました


私も。schema-data-schema手法の問題は、フィールド/モデルに異なる名前が付けられることです。正規名を使用してディスパッチャーを有効にすると、これが問題になることがあります...
Jonathan

私はこれを試してみましたが、名前の競合があったため機能しませんでした。FKはまったく同じですが、名前が異なりました。検証されませんでした。したがって、これを行わないでください。
Gezim

2
@jonathan、彼は別の名前を望んでいます!... @pilgrim、いくつかのコードを投稿しますか?私はこれを今週数回行っていますが、モデルが検証されない場合、サウスは移行を作成しません。
sjh 2010

それはうまくいきますが、おそらく他の人々が提案した「rename_column」よりも遅いでしょう。MySQLが「ALTER TABLE ...列の名前を変更」(またはそれが何であれ)を非常に迅速に実行できることを知っています。
ロリー

1
@Rory db.rename_columnは制約の名前を変更しないため、手動で処理する必要があります。それを行うのを忘れた場合でも、古いカラム名を使用している制約があることに気付かない場合を除いて、移行は機能します。問題が単なる表面的なものなのか、または制約を操作または削除する必要がある将来の移行でSouthがそれを見つけることができないのかは、私にはわかりません。とにかく、sjhが示唆するようにここでそれを行うのが安全な方法です。Southにそれが何を理解すべきかを理解させることができます。
ルイ、

10

Django 1.7はマイグレーションを導入したので、マイグレーションを管理するために追加のパッケージをインストールする必要さえありません。

モデルの名前を変更するには、まず空のマイグレーションを作成する必要があります:

$ manage.py makemigrations <app_name> --empty

次に、移行のコードを次のように編集する必要があります。

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

その後、実行する必要があります:

$ manage.py migrate <app_name>

5

モデルを変更makemigrationsして1.9 で実行するだけです

Djangoは、単一のフィールドを削除して作成したことを自動的に検出し、次のように尋ねます。

Did you rename model.old to model.new (a IntegerField)? [y/N]

はいと言うと、適切な移行が作成されます。マジック。


0
  1. southプロジェクト設定ファイルのインストール済みアプリに追加します。
  2. 追加/変更されたフィールド/テーブルをコメント化します。
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. フィールドのコメントを外して、変更されたフィールドに書き込みます
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

「pycharm」を使用している場合は、「manage.py」の代わりに「ctrl + shift + r」を使用し、パラメーターに「shift」を使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.