どんな移行モデルの一djangoアプリと新しい。
-
12-09-2019 - |
質問
いdjangoアプリにつモデルです。このモデルは別のアプリです。い南置の移動がいいかもしれませんがこれに対応できます。したいので移動のモデルの古いアプリを新しい。
また、うん、これらを必要とする繰り返し処理ができるよう、移行の生産システムです。
解決
南を使用して移行する方法。
私たちは2つのアプリを得たとしましょう:共通および特定ます:
をmyproject/
|-- common
| |-- migrations
| | |-- 0001_initial.py
| | `-- 0002_create_cat.py
| `-- models.py
`-- specific
|-- migrations
| |-- 0001_initial.py
| `-- 0002_create_dog.py
`-- models.py
は、今、私たちは、特定のアプリに(正確にspecific.models.catに)モデルcommon.models.catを移動したいです。 まず、ソースコードの変更を行ってから実行します:
$ python manage.py schemamigration specific create_cat --auto
+ Added model 'specific.cat'
$ python manage.py schemamigration common drop_cat --auto
- Deleted model 'common.cat'
myproject/
|-- common
| |-- migrations
| | |-- 0001_initial.py
| | |-- 0002_create_cat.py
| | `-- 0003_drop_cat.py
| `-- models.py
`-- specific
|-- migrations
| |-- 0001_initial.py
| |-- 0002_create_dog.py
| `-- 0003_create_cat.py
`-- models.py
今、私たちは両方の移行ファイルを編集する必要があります:
#0003_create_cat: replace existing forward and backward code
#to use just one sentence:
def forwards(self, orm):
db.rename_table('common_cat', 'specific_cat')
if not db.dry_run:
# For permissions to work properly after migrating
orm['contenttypes.contenttype'].objects.filter(
app_label='common',
model='cat',
).update(app_label='specific')
def backwards(self, orm):
db.rename_table('specific_cat', 'common_cat')
if not db.dry_run:
# For permissions to work properly after migrating
orm['contenttypes.contenttype'].objects.filter(
app_label='specific',
model='cat',
).update(app_label='common')
<時間>
#0003_drop_cat:replace existing forward and backward code
#to use just one sentence; add dependency:
depends_on = (
('specific', '0003_create_cat'),
)
def forwards(self, orm):
pass
def backwards(self, orm):
pass
これで、両方のアプリケーションの移行は、変更を認識しているとの生活は、ちょうど少し:-)吸います 移行の間にこの関係を設定すると、成功の鍵です。 今、あなたがしなければます:
python manage.py migrate common
> specific: 0003_create_cat
> common: 0003_drop_cat
両方の移行を行います、と
python manage.py migrate specific 0002_create_dog
< common: 0003_drop_cat
< specific: 0003_create_cat
物事をダウンに移行されます。
スキーマのアップグレードのために、私は、共通のアプリを使用してダウングレードのために、私は特定のアプリを使用することをの注意してください。ここでは、依存関係がどのように動作するかだからです。の
他のヒント
の構築に Potr Czachur's 答え, 状を伴うForeignKeysはますます複雑化の取り扱いにあたって若干異なる。
(以下の例を挙げ common
や specific
アプリとの現在の回答).
# common/models.py
class Cat(models.Model):
# ...
class Toy(models.Model):
belongs_to = models.ForeignKey(Cat)
# ...
そうした変化を
# common/models.py
from specific.models import Cat
class Toy(models.Model):
belongs_to = models.ForeignKey(Cat)
# ...
# specific/models.py
class Cat(models.Model):
# ...
走
./manage.py schemamigration common --auto
./manage.py schemamigration specific --auto # or --initial
生以下の移動によって意図的に無視しDjango ContentType変化を見た参照する回答の取り扱い方法に):
# common/migrations/0009_auto__del_cat.py
class Migration(SchemaMigration):
def forwards(self, orm):
db.delete_table('common_cat')
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.Cat']))
def backwards(self, orm):
db.create_table('common_cat', (
# ...
))
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))
# specific/migrations/0004_auto__add_cat.py
class Migration(SchemaMigration):
def forwards(self, orm):
db.create_table('specific_cat', (
# ...
))
def backwards(self, orm):
db.delete_table('specific_cat')
ご覧のとおり、FKれを機に変えなければいけな参考に新しい。して追加する必要があり、依存関係のようにしていたの移動に適用されます(このテーブルに存在し続ける前に努めの追加FKでも確認する必要があり圧延後方にでもで の依存関係が適用され、逆方向の.
# common/migrations/0009_auto__del_cat.py
class Migration(SchemaMigration):
depends_on = (
('specific', '0004_auto__add_cat'),
)
def forwards(self, orm):
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.Cat']))
def backwards(self, orm):
db.rename_table('specific_cat', 'common_cat')
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))
# specific/migrations/0004_auto__add_cat.py
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('common_cat', 'specific_cat')
def backwards(self, orm):
pass
当たりの 南書, depends_on
この 0004_auto__add_cat
運前 0009_auto__del_cat
移行作業はもちろんのこと転送 ですが、 逆の順序での移行作業はもちろんのこと後退.また左 db.rename_table('specific_cat', 'common_cat')
の specific
ロールバック、 common
ロールバックに失敗しようとする場合の移行ForeignKeyでのテーブル参照されるテーブルな存在します。
このづくりを進めている現実世界での"状況により、既存のソリューションや人ます。感謝!
のモデルは非常に緊密に非常に簡単ですので、移動、アプリケーションに結合されていません。さらに簡単に - - あなたのアプリを移動したい場合は、SQLのALTER TABLE
文によって、データベーステーブルの名前を変更するか、どちらかので、Djangoは、データベーステーブルの名前でアプリ名を使用して、単に<のhref = "HTTPを使用します/お使いのモデルのdb_table
クラスで/docs.djangoproject.com/en/dev/ref/models/options/#db-table」のrel = "noreferrer"> Meta
パラメータには、古い名前を参照します。
あなたがこれまでにどこでもあなたのコード内のcontenttypesのか、一般的な関係を使用している場合、あなたはおそらく、既存の関係が保存されるように、動いているモデルで、ContentTypeを指すのapp_label
の名前を変更したいと思うでしょう。
もちろん、一番簡単な方法は、完全にデータベーステーブルをドロップして、再度./manage.py syncdb
を実行することです。
ここでPotrの優れたソリューションへの1つの以上の修正です。 を特定/ 0003_create_catに以下を追加の
depends_on = (
('common', '0002_create_cat'),
)
この依存関係が設定されていない場合、南はcommon_cat
テーブルはを特定/ 0003_create_cat の時点で存在していることを保証するものではありませんあなたにdjango.db.utils.OperationalError: no such table: common_cat
エラーを投げて、実行されます。
南は辞書順のでマイグレーションを実行しますセットする。 common
がspecific
の前に来るので、すべてのcommon
の移行は、テーブルの名前を変更する前に実行になるだろう、それはおそらくPotrで示す元の例では再現できないでしょう。しかし、あなたは、あなたがこの問題に実行されますcommon
するapp2
とspecific
するapp1
の名前を変更する場合。
プロセス私は現在に定住しました。
この元々の上に構築されました Potr Czachurの回答する そして、をhref="https://stackoverflow.com/a/12080790"> 南0.8.4を使用して
ステップ1.発見の子の外部キー関係
# Caution: This finds OneToOneField and ForeignKey.
# I don't know if this finds all the ways of specifying ManyToManyField.
# Hopefully Django or South throw errors if you have a situation like that.
>>> Cat._meta.get_all_related_objects()
[<RelatedObject: common:toy related to cat>,
<RelatedObject: identity:microchip related to cat>]
だから、この拡張された場合には、我々のような別の関連のモデルを発見しました
# Inside the "identity" app...
class Microchip(models.Model):
# In reality we'd probably want a ForeignKey, but to show the OneToOneField
identifies = models.OneToOneField(Cat)
...
ステップ2.移行
を作成します。# Create the "new"-ly renamed model
# Yes I'm changing the model name in my refactoring too.
python manage.py schemamigration specific create_kittycat --auto
# Drop the old model
python manage.py schemamigration common drop_cat --auto
# Update downstream apps, so South thinks their ForeignKey(s) are correct.
# Can skip models like Toy if the app is already covered
python manage.py schemamigration identity update_microchip_fk --auto
ステップ3.ソースコントロール:これまでの変更をコミットします。
あなたが更新アプリに移行を書いてチームメイトのようなマージの競合に実行する場合、それより再現可能なプロセス作ります。
ステップ4.移行の間の依存関係を追加します。
基本的にcreate_kittycat
は、すべての現在の状態に依存し、すべてが、その後create_kittycat
に依存します。
# create_kittycat
class Migration(SchemaMigration):
depends_on = (
# Original model location
('common', 'the_one_before_drop_cat'),
# Foreign keys to models not in original location
('identity', 'the_one_before_update_microchip_fk'),
)
...
# drop_cat
class Migration(SchemaMigration):
depends_on = (
('specific', 'create_kittycat'),
)
...
# update_microchip_fk
class Migration(SchemaMigration):
depends_on = (
('specific', 'create_kittycat'),
)
...
ステップ5.テーブル、我々がしたいの変更を変更します。
# create_kittycat
class Migration(SchemaMigration):
...
# Hopefully for create_kittycat you only need to change the following
# 4 strings to go forward cleanly... backwards will need a bit more work.
old_app = 'common'
old_model = 'cat'
new_app = 'specific'
new_model = 'kittycat'
# You may also wish to update the ContentType.name,
# personally, I don't know what its for and
# haven't seen any side effects from skipping it.
def forwards(self, orm):
db.rename_table(
'%s_%s' % (self.old_app, self.old_model),
'%s_%s' % (self.new_app, self.new_model),
)
if not db.dry_run:
# For permissions, GenericForeignKeys, etc to work properly after migrating.
orm['contenttypes.contenttype'].objects.filter(
app_label=self.old_app,
model=self.old_model,
).update(
app_label=self.new_app,
model=self.new_model,
)
# Going forwards, should be no problem just updating child foreign keys
# with the --auto in the other new South migrations
def backwards(self, orm):
db.rename_table(
'%s_%s' % (self.new_app, self.new_model),
'%s_%s' % (self.old_app, self.old_model),
)
if not db.dry_run:
# For permissions, GenericForeignKeys, etc to work properly after migrating.
orm['contenttypes.contenttype'].objects.filter(
app_label=self.new_app,
model=self.new_model,
).update(
app_label=self.old_app,
model=self.old_model,
)
# Going backwards, you probably should copy the ForeignKey
# db.alter_column() changes from the other new migrations in here
# so they run in the correct order.
#
# Test it! See Step 6 for more details if you need to go backwards.
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))
db.alter_column('identity_microchip', 'identifies_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['common.Cat']))
# drop_cat
class Migration(SchemaMigration):
...
def forwards(self, orm):
# Remove the db.delete_table(), if you don't at Step 7 you'll likely get
# "django.db.utils.ProgrammingError: table "common_cat" does not exist"
# Leave existing db.alter_column() statements here
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.KittyCat']))
def backwards(self, orm):
# Copy/paste the auto-generated db.alter_column()
# into the create_kittycat migration if you need backwards to work.
pass
# update_microchip_fk
class Migration(SchemaMigration):
...
def forwards(self, orm):
# Leave existing db.alter_column() statements here
db.alter_column('identity_microchip', 'identifies_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['specific.KittyCat']))
def backwards(self, orm):
# Copy/paste the auto-generated db.alter_column()
# into the create_kittycat migration if you need backwards to work.
pass
ステップあなたは(が)仕事とKeyError例外が逆方向に動作させるには、下位必要がある場合にのみ6。
# the_one_before_create_kittycat
class Migration(SchemaMigration):
# You many also need to add more models to South's FakeORM if you run into
# more KeyErrors, the trade-off chosen was to make going forward as easy as
# possible, as that's what you'll probably want to do once in QA and once in
# production, rather than running the following many times:
#
# python manage.py migrate specific <the_one_before_create_kittycat>
models = {
...
# Copied from 'identity' app, 'update_microchip_fk' migration
u'identity.microchip': {
'Meta': {'object_name': 'Microchip'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'identifies': ('django.db.models.fields.related.OneToOneField', [], {to=orm['specific.KittyCat']})
},
...
}
ステップ7:テストして - あなたの実際の生活状況のために十分ではないかもしれない私のためにどのような作品:)
python manage.py migrate
# If you need backwards to work
python manage.py migrate specific <the_one_before_create_kittycat>
したがって、上記の動作しませんでした@Potrから元の応答を使用して 私のために南0.8.1とDjango 1.5.1に。私がやったことを投稿しています それは他の人に役に立つことを期待して、以下の私のために働くます。
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('common_cat', 'specific_cat')
if not db.dry_run:
db.execute(
"update django_content_type set app_label = 'specific' where "
" app_label = 'common' and model = 'cat';")
def backwards(self, orm):
db.rename_table('specific_cat', 'common_cat')
db.execute(
"update django_content_type set app_label = 'common' where "
" app_label = 'specific' and model = 'cat';")
私はダニエルローズマンは、彼の答えで提案ものの一つのより明示的なバージョンを与えるつもりだ...
あなただけのモデルのdb_table
メタ属性を変更する場合は、あなたが複雑な南の移行を回避することができます(あなたがsyncdb
を落としていた場合、代わりに新しい名前のDjangoはそれを与えるだろう)既存のテーブル名を指すように移動してきました。例えばます:
オリジナルます:
# app1/models.py
class MyModel(models.Model):
...
移動後:
# app2/models.py
class MyModel(models.Model):
class Meta:
db_table = "app1_mymodel"
今、あなただけのapp_label
テーブルにMyModel
ためdjango_content_type
を更新するために、データの移行を行う必要があり、あなたが...行くに良いことがあります。
ファイル名を指定して実行の./manage.py datamigration django update_content_type
はその後、南があなたのために作成したファイルを編集します:
def forwards(self, orm):
moved = orm.ContentType.objects.get(app_label='app1', model='mymodel')
moved.app_label = 'app2'
moved.save()
def backwards(self, orm):
moved = orm.ContentType.objects.get(app_label='app2', model='mymodel')
moved.app_label = 'app1'
moved.save()