2012-07-13 30 views
4

我正在使用south来管理迁移,并且我已经到了一个角落。基本上,我有以下设置:如何在从一对一移动到一对多时执行数据迁移

应用1

class A(models.Model): 
    # bunch of attributes 

应用2

class B(models.Models): 
    instance_a = models.OneToOneField(A, null=True, blank=True, 
            editable=False) 

现在,我想从这个去这个:

应用1

class A(models.Model): 
    instance_b = models.ForeignKey(B, null=True, blank=True) 

应用2

class B(models.Models): 
    # other attributes 

我的主要问题是,我不能松动的数据。因此,基本上在迁移结束时,先前映射到对象B的所有对象A都应该保留该映射。例如,如果id为7的对象A映射到id为8的对象B,则在此过程结束时应保留此映射。

我试图从模式迁移与临时占位符和数据迁移混合的几件事情。然而,我总是在同一个地方,这是数据迁移执行时,我不再有以前的关系,以访问正确的属性。例如,B.instance_a不再可用。

我想两件事情你的意见:

  • 首先,在这一切可行的使用正南方迁移。
  • 其次,我该如何着手。

感谢

回答

3

一段时间后,我得到了一个程序与django-south可能帮助别人最后。关键在南方的depends_on功能(http://south.aeracode.org/wiki/Dependencies)。我这样做是在4个步骤:

首先

  • 模型A创建外键的值的占位符。

所以模型A变为:

class A(models.Model): 
    instance_b_placeholder = models.ForeignKey(A, null=True, blank=True) 

现在只需运行manage.py schemamigration app1 --auto

  • 创建datamigration所以我们可以复制的价值。目标是将数据复制到数据库中,然后重命名属性并删除旧数据。问题manage.py datamigration app1 update_fields。我选择保留app1的数据迁移。如果您不这样做,只需确保它在之前的迁移之后运行即可。

这里将datamigration编码:

# Forwards: 

for b in orm['app2.B'].objects.filter(instance_b__isnull=False): 
     b.instance_a.instance_b_placeholder = b 
     b.instance_a.save() 

# Backwards: 

for r in orm['app1.A'].objects.filter(instance_b_placeholder__isnull=False): 
     r.instance_b_placeholder.instance_a = r 
     r.instance_b_placeholder.save() 

  • 从模型B删除字段instance_b并确保让移民跑在前面创建的一个后步。

型号B变为:

class B(models.Model): 
    # etc... 

问题manage.py schemamigration app2 --auto和编辑迁移添加先前迁移到depends_on

depends_on = (
    ("app1", "<migration_number>_update_fields"), 
) 

第四步

  • 重命名占位符。这是通过更改代码中的名称并编辑迁移来实现的。编辑是必要的,因为south倾向于删除并添加一个新列,但我们只希望它重新命名列。

  • 此迁移应该运行在最后位置,所以我使它依赖于上一个。

下面的代码:

depends_on = (
    ("app2", "<previous_migration_here>"), 
) 

# Forwards: 

    db.rename_column('app1_a', 'instance_b_placeholder_id', 'instance_b_id') 

# Backwards: 

    db.rename_column('app1_a', 'instance_b_id', 'instance_b_placeholder_id') 

所以这是它。我不知道是否有其他方法可以做到这一点,但至少这对我有帮助。

相关问题