私はSouthのサイト、Google、SOでこれに対する答えを探していましたが、これを行う簡単な方法を見つけることができませんでした。
Southを使用してDjangoモデルの名前を変更します。次のものがあるとします。
_class Foo(models.Model):
name = models.CharField()
class FooTwo(models.Model):
name = models.CharField()
foo = models.ForeignKey(Foo)
_
fooをBarに変換したい、つまり
_class Bar(models.Model):
name = models.CharField()
class FooTwo(models.Model):
name = models.CharField()
foo = models.ForeignKey(Bar)
_
単純にするために、名前をFoo
からBar
に変更しようとしていますが、foo
のFooTwo
メンバーは今のところ無視します。
Southを使用してこれを行う最も簡単な方法は何ですか?
db.rename_table('city_citystate', 'geo_citystate')
ですが、この場合の外部キーの修正方法はわかりません。最初の質問に答えるために、単純なモデル/テーブルの名前変更は非常に簡単です。次のコマンドを実行します。
./manage.py schemamigration yourapp rename_foo_to_bar --empty
(更新2:以下の警告を避けるため、--auto
の代わりに--empty
を試してください。ヒントを提供してくれた@KFBに感謝します。)
Southの古いバージョンを使用している場合、startmigration
の代わりにschemamigration
が必要です。
次に、移行ファイルを次のように手動で編集します。
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('yourapp_foo', 'yourapp_bar')
def backwards(self, orm):
db.rename_table('yourapp_bar','yourapp_foo')
モデルクラスでdb_table
Metaオプションを使用すると、これをより簡単に実現できます。しかし、それを行うたびに、コードベースの従来の重みが増えます。クラス名がテーブル名と異なると、コードの理解と保守が難しくなります。わかりやすくするために、このような単純なリファクタリングを完全にサポートしています。
(更新)実稼働環境でこれを試したところ、移行を適用しようとしたときに奇妙な警告が表示されました。と言いました:
The following content types are stale and need to be deleted: yourapp | foo Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'.
私は「いいえ」と答え、すべてがうまくいくように見えました。
models.py
で変更を行ってから実行します
./manage.py schemamigration --auto myapp
移行ファイルを調べると、テーブルが削除され、新しいテーブルが作成されることがわかります。
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'Foo'
db.delete_table('myapp_foo')
# Adding model 'Bar'
db.create_table('myapp_bar', (
...
))
db.send_create_signal('myapp', ['Bar'])
def backwards(self, orm):
...
これは、あなたが望むものとはまったく異なります。代わりに、移行を次のように編集します。
class Migration(SchemaMigration):
def forwards(self, orm):
# Renaming model from 'Foo' to 'Bar'
db.rename_table('myapp_foo', 'myapp_bar')
if not db.dry_run:
orm['contenttypes.contenttype'].objects.filter(
app_label='myapp', model='foo').update(model='bar')
def backwards(self, orm):
# Renaming model from 'Bar' to 'Foo'
db.rename_table('myapp_bar', 'myapp_foo')
if not db.dry_run:
orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')
update
ステートメントがない場合、db.send_create_signal
呼び出しは、新しいモデル名で新しいContentType
を作成します。ただし、データベースオブジェクトがそれを指している場合(たとえば、update
を介して)既に持っているContentType
をGenericForeignKey
する方が良いでしょう。
また、名前を変更したモデルの外部キーである列の名前を変更した場合は、忘れずに
db.rename_column(myapp_model, foo_id, bar_id)
サウスはそれ自体ができません-Bar
がFoo
を使用していたことをどのように認識するのでしょうか?これは、私がカスタム移行を作成するようなものです。上記で行ったようにコードでForeignKey
を変更できます。これは、適切なフィールドとテーブルの名前を変更する場合にすぎません。これは任意の方法で実行できます。
最後に、本当にこれを行う必要がありますか?モデルの名前を変更する必要はまだありません-モデル名は実装の詳細にすぎません-特に verbose_name
メタオプション。