Django模型拆分时,数据迁移时如何保持ForeignKey和ManyToMany关系?

When splitting a Django model, How to keep ForeignKey and ManyToMany relationships during data migration?

我的 Django 模型做得太多了。这是该模型的一个简化示例。基本上,它可以表示四种不同的 Entity 类型,并且有指向其他实体的递归 ForeignKey 和 ManyToMany 关系。

此项目目前使用 Django 1.8.x 和 Python 2.7.x,但如果解决方案需要,我可以升级它们。

class Entity(models.Model):
    """
    Films, People, Companies, Terms & Techniques
    """

    class Meta:
        ordering = ['name']
        verbose_name_plural = 'entities'

    # Types:
    FILM = 'FILM'
    PERSON = 'PERS'
    COMPANY = 'COMP'
    TERM = 'TERM'
    TYPE_CHOICES = (
        (FILM, 'Film'),
        (PERSON, 'Person'),
        (COMPANY, 'Company'),
        (TERM, 'Term/Technique'),
    )

    created = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated = models.DateTimeField(auto_now_add=False, auto_now=True)
    type = models.CharField(max_length=4, choices=TYPE_CHOICES, default=FILM)
    slug = models.SlugField(blank=True, unique=True, help_text="Automatically generated")
    name = models.CharField(max_length=256, blank=True)
    redirect = models.ForeignKey('Entity', related_name='entity_redirect', blank=True, null=True, help_text="If this is an alias (see), set Redirect to the primary entry.")
    cross_references = models.ManyToManyField('Entity', related_name='entity_cross_reference', blank=True, help_text="This is a 'see also' — 'see' should be performed with a redirect.")
    [... and more fields, some of them type-specific]

我意识到这很混乱,我想删除 'type' 并制作一个 EntityBase class 来抽象出所有公共字段,并创建新的 [ =13=、PersonCompanyTerm 模型继承自 EntityBase 抽象基础 class.

创建新模型后,我想我了解了如何编写数据迁移以将所有字段数据移动到新模型(迭代来自 Entity 的对象,通过 [=19 过滤) =],在适当的新模型中创建新对象)... 除了 ForeignKey 和 ManyToMany 关系。也许我的想法是错误的,但是在迁移过程中,当关系指向的新对象可能还不存在时,我该如何转移这些关系?

我怀疑这可能意味着多步迁移,但我还没有找到正确的方法。

m2m 和 fk 字段没有什么神奇之处。这是我要遵循的程序...可能有点生硬,但可以完成工作:

  1. 制作数据库的BACKKKUPPPPPPppp!!
  2. 再次备份!
  3. 创建新模型并迁移
  4. 编写一个新的数据迁移,将手动迭代现有模型并更新新模型,one-by-one。不要害怕这里的 for 循环,除非你在数据库中有数百万个条目。
  5. 删除冗余模型and/or字段,为此进行迁移。
  6. 运行 那些迁移:)

实际上,这意味着从 "BACKKKUPPPPPPppp" 进行大量恢复,直到迁移恰到好处。

需要注意的一件小事:

如果模型尚未保存,则 M2m 字段无法获取任何值(因为模型在首次保存时获取其 ID)。我会在手动迁移中做类似的事情:

new_instance = NewModel()
new_instance.somefield = "whatever"
new_instance.meaning = 42
....
new_instance.save()
new_instance.that_m2m_field.add(some_related_obj)

当然,请务必详细阅读 the docs,尤其是关于导入模型的部分 class - 您不能只导入它 from myapp.models import MyModel ,改为:

MyModel = apps.get_model("myapp", "MyModel")

一个可能的绊脚石可能是您计划引入的模型继承。通常,您需要在 child 模型上操作,并在需要时从那里访问 parent。 Parent 可以通过隐式 ptr 属性访问 - 在您的示例中它将是 entitybase_ptr 或类似的东西(这只是一个 OneToOne 字段)。然而,从另一个方向(从 parent 到未知的 child)并不那么简单,因为 parent 事先不知道它的 class 是什么child.