我想使用South将字段 honk 和它的数据从一个模型移动到另一个模型:
class Foo(models.Model):
foofield = models.CharField()
honk = models.PositiveIntegerField()
class Bar(models.Model):
barfield = models.CharField()
我以前使用3次单独的迁移完成了这项工作:
我已经学会了there isn't much of a difference between schema and data migrations in South,所以我想也许这样的事情可能会起作用(这就是上面的三次迁移只是一次):
class Migration(DataMigration):
def forwards(self, orm):
# add column
db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)
# copy data
for foo in Foo.objects.all():
# find the right bar here and then ...
bar.honk = foo.honk
bar.save()
# remove old column
db.delete_column('myapp_foo', 'honk')
这会起作用还是会失败,因为我(南方冻结) orm 还不知道Bar.honk呢?或者我做错了,在一次迁移中有更好的方法来做这种事情吗?
答案 0 :(得分:15)
因为这个问题为我赢得了Tumbleweed badge,所以我自己也进行了尝试。这是我发现的。
因为ORM冻结仅包含要迁移到的架构。因此,在上面的示例中, foo.honk 在数据迁移期间( for 循环)将无法访问,因为它在架构迁移期间被删除,因此它不是在冻结的ORM中。此外,如果您尝试访问数据,您将获得DatabaseError异常,因为数据库中的列尚未与模型中的列匹配(即,如果您尝试在 db.add_column 之前访问任何内容)
看起来没有简单的快捷方式,做这样的事情确实需要上面提到的3次迁移。
答案 1 :(得分:1)
从这个角度来看,文档是缺乏的,但是如果你在迁移过程中修改ORM的冻结部分,自己添加缺少的字段,那么它就可以访问:我的意思是,在南迁移期间,你必须使用冻结的ORM ,因为将来您迁移时,Foo
模型可能已丢失honk
字段。
我认为如果您修改冻结的ORM声明,如下所示
models = {
'app.foo': {
'Meta': {'object_name': 'Foo'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'foofield': ('django.db.models.fields.CharField', [],{'max_length':666}),
'honk': ('django.db.models.fields.PositiveIntegerField', [], {}),
},
'app.bar': {
'Meta': {'object_name': 'Bar'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'barfield': ('django.db.models.fields.CharField', [],{'max_length':666}),
'honk': ('django.db.models.fields.PositiveIntegerField', [], {}),
},
}
complete_apps = ['app']
symmetrical = True
一切都会奏效:)
诀窍是每个模型中字段honk
的定义,显然数据库中的列必须存在
class Migration(DataMigration):
def forwards(self, orm):
# add column
db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)
# copy data
for foo in Foo.objects.all():
# find the right bar here
bar = orm.Bar.objects.get(**whatever)
bar.honk = foo.honk
bar.save()
# remove old column
db.delete_column('myapp_foo', 'honk')
@ acjohnson55 symmetrical = True
所指出的PS:非常重要
答案 2 :(得分:0)
这对我有用:
def migratedata(orm):
# copy data, need to lookup model through orm.
for foo in orm['myapp.foo'].objects.all():
# find the right bar here and then ...
bar.honk = foo.honk
bar.save()
class Migration(SchemaMigration):
def forwards(self, orm):
# add column
db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)
# migrate data
if not db.dry_run:
migratedata(orm)
# remove old column
db.delete_column('myapp_foo', 'honk')
但是,我不推荐它,因为它容易搞砸。需要特别注意唯一性和操作顺序(IOW,删除相关字段后不要迁移数据(:)
答案 3 :(得分:0)
正如英格玛所提到的,南方的ORM会在特定的时间点被冻结,这会阻止您访问ORM不知道的列。但是,实际上有一种解决方法:您不必使用ORM,甚至根本不需要任何ORM;相反,你可以execute raw SQL queries
例如,而不是
for foo in Foo.objects.all():
print foo.honk
你可以这样做:
cursor.execute('SELECT "honk" FROM "myapp_foo"')
for honk, in cursor.fetchall():
print honk