我可以将架构和数据(南)迁移合并为一个吗?

时间:2012-01-06 10:11:56

标签: django-south

我想使用South将字段 honk 和它的数据从一个模型移动到另一个模型:

class Foo(models.Model):
    foofield = models.CharField()
    honk = models.PositiveIntegerField()

class Bar(models.Model):
    barfield = models.CharField()

我以前使用3次单独的迁移完成了这项工作:

  1. 架构迁移,将 honk 添加到
  2. 数据迁移,将所有 Foo.honk 数据复制到 Bar.honk
  3. 另一个架构迁移,从 Foo
  4. 中删除 honk

    我可以在一次迁移中执行这三个步骤吗?

    我已经学会了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呢?或者我做错了,在一次迁移中有更好的方法来做这种事情吗?

4 个答案:

答案 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