Djangoプロジェクトには、すでにデータが含まれているデータベーステーブルがあります。その列のデータを失わずにフィールド名を変更したいと思います。私の元々の計画は、実際にデータベーステーブルの名前を変更しない方法でのモデルフィールド名(db_column
列パラメーターを使用):
元のモデル:
class Foo(models.Model):
orig_name = models.CharField(max_length=50)
新しいモデル:
class Foo(models.Model):
name = models.CharField(max_length=50, db_column='orig_name')
ただし、Southのschemamigration --auto
を実行すると、元の列orig_name
を削除し、新しい列name
を追加する移行スクリプトが生成されます。これにより、その列。 (データベーステーブルの列の名前を変更せずにモデルフィールド名を変更できるというのがdb_columnの理解であったため、Southがdbの列の名前を変更する理由についても混乱しています)。
Dbフィールドを変更せずにモデルフィールドを変更しても問題が解決しない場合は、次のように名前をもっと簡単に変更できると思います。
元のモデル:
class Foo(models.Model):
orig_name = models.CharField(max_length=50)
新しいモデル:
class Foo(models.Model):
name = models.CharField(max_length=50)
最終的にどの戦略を使用するかに関係なく(最初の方法を優先しますが、2番目の方法は許容できると思います)、私の主な関心事は、その列に既にあるデータを失わないようにすることです。
これには複数ステップのプロセスが必要ですか? (1.列の追加、2。古い列から新しい列へのデータの移行、3。元の列の削除など)または、db.alter_column
のようなもので移行スクリプトを変更できますか?
列の名前を変更しながらその列のデータを保持するための最良の方法は何ですか?
Django 1.8+の回答を追加します(Djangoネイティブの移行ではなく、Southではありません)。
最初にdb_column
プロパティを追加し、次にフィールドの名前を変更する移行を行います。 Djangoは、最初は何もしない(db_column
を変更しないため)であり、2番目は何もしない(スキーマを作成しないため)と理解しています実際にログを調べて、スキーマの変更がないことを確認しました...
operations = [
migrations.AlterField(
model_name='mymodel',
name='oldname',
field=models.BooleanField(default=False, db_column=b'oldname'),
),
migrations.RenameField(
model_name='mymodel',
old_name='oldname',
new_name='newname',
),
]
修正は非常に簡単です。ただし、マイグレーションを自分で変更する必要があります。
列を削除して追加する代わりに、 db.rename_column
を使用します。 schemamigration --auto
によって作成された移行を変更するだけです。
更新2
Django 2.2でも同じように機能します
更新1
Django 2.0.9でテストしました。フィールドの名前が変更されたかどうかを自動的に検出し、削除して新しいフィールドを作成する代わりに名前を変更するオプションを提供します-
最初の答え
投稿がまだ役立つ場合。
Django 2.0の場合+モデルのフィールドの名前を変更するだけ
class Foo(models.Model):
orig_name = models.CharField(max_length=50)
に
class Foo(models.Model):
name = models.CharField(max_length=50)
python manage.py makemigrations
古いフィールドを削除して新しいフィールドを追加する操作を含む移行が生成されます。
先に進んで、それを次のように変更してください。
operations = [
migrations.RenameField(
model_name='foo',
old_name='orig_name',
new_name='name')
]
python manage.py migrate
データを失うことなく、DBの列の名前を変更します。
実際にDjango 1.10を使用して、モデルのフィールドの名前を変更してからmakemigrationsを実行すると、操作がすぐに識別されます(つまり、1つのフィールドが消え、別のフィールドが代わりに表示されます)。
$ ./manage.py makemigrations
Did you rename articlerequest.update_at to articlerequest.updated_at (a DateTimeField)? [y/N] y
Migrations for 'article_requests':
article_requests/migrations/0003_auto_20160906_1623.py:
- Rename field update_at on articlerequest to updated_at
私はこの状況に遭遇しました。モデルのフィールド名を変更したいが、列名は同じにしたかった。
私がやった方法は、schemamigration --empty [app] [some good name for the migration]
を実行することです。問題は、Southに関する限り、モデル内のフィールド名の変更は、処理する必要がある変更であるということです。したがって、移行を作成する必要があります。ただし、データベース側で実行する必要があることは何もないことはわかっています。 したがって、空の移行はデータベースで不必要な操作を実行することを避け、それでも変更と見なされるものを処理するサウスのニーズを満たします。
loaddata
を使用するか、Djangoのテストフィクスチャ機能(裏でloaddata
を使用)を使用する場合は注意してください。フィクスチャはデータベースフィールド名ではなくモデルフィールド名に基づいているため、新しいフィールド名を使用するようにフィクスチャを更新する必要があります。
データベースで列名が変更される場合、列の移行にdb.rename_column
を使用することはお勧めしません。私は この答え でsjhによって記述された方法を使用します:
新しい列を1つのschemamigrationとして追加し、次にデータ移行を作成して値を新しいフィールドに移動し、2番目のschemamigrationで古い列を削除しました
その質問の コメント で述べたように、db.rename_column
の問題は、列と一緒に制約の名前を変更しないことです。問題が単なる表面的なものであるか、それとも制約が見つからないために将来の移行が失敗する可能性があるかは、私には不明です。
手動で移行ファイルを編集せずにフィールドの名前を変更することが可能です。
python3 manage.py makemigrations
python3 manage.py makemigrations
プロンプトが表示されます:
[〜#〜] model [〜#〜] .OLD_FIELD_NAMEを[〜#〜] model [〜#〜]に名前変更しましたか? NEW_FIELD_NAME(a ForeignKey)? [y/N] y
これにより、1つではなく2つの移行ファイルが生成されますが、どちらの移行も自動生成されます。
この手順はDjango 1.7+で機能します。
私はDjango 1.7.7でこの状況に遭遇しました。私は私のために働いた次のことをすることになりました。
./manage.py makemigrations <app_name> --empty
データベースに影響を与えないmigrations.RenameField
の単純なサブクラスを追加しました:
class RenameFieldKeepDatabaseColumn(migrations.RenameField):
def database_backwards(self, app_label, schema_editor, from_state, to_state):
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
pass