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 不再可用。

我想听听你对两件事的看法:

  • 首先,仅使用南迁移是否可行。
  • 其次,我该如何进行。

谢谢

4

1 回答 1

3

终于过了一段时间,我得到了一个django-south可能对其他人有帮助的程序。关键在于南的depends_on功能(http://south.aeracode.org/wiki/Dependencies)。我分 4 步完成:

首先

  • 为 model 中的外键值创建一个占位符A

所以模型A变为:

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

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

第二

  • 创建一个数据迁移,以便我们可以复制这些值。目标是在数据库中复制数据,然后重命名属性并删除旧属性。问题manage.py datamigration app1 update_fields。我选择将数据迁移保留在app1. 如果您不这样做,请确保它在上次迁移之后运行。

这是编码的数据迁移:

# 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()

第三

  • instance_b从模型中删除字段,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')

就是这样了。我不知道是否还有很多其他方法可以做到这一点,但至少这对我有所帮助。

于 2012-09-20T20:38:10.210 回答