Django:将多态模型迁移回单个基类

时间:2017-07-06 12:22:30

标签: python django database-migration

让我们假设I have a polymorphic model,我想摆脱它。

class AnswerBase(models.Model):

    question = models.ForeignKey(Question, related_name="answers")
    response = models.ForeignKey(Response, related_name="answers")


class AnswerText(AnswerBase):
    body = models.TextField(blank=True, null=True)

class AnswerInteger(AnswerBase):
    body = models.IntegerField(blank=True, null=True)

当我想得到所有答案时,我永远无法访问“正文”,或者我需要尝试通过反复试验来获取子类的实例。

# Query set of answerBase, no access to body   
AnswerBase.objects.all()
question = Question.objects.get(pk=1)
# Query set of answerBase, no access to body (even with django-polymorphic)
question.answers.all()

我不想因为性能而使用django-polymorphic,因为它似乎不适用于foreignKey关系,因为我不希望我的模型太复杂。所以我希望这种多态架构成为this simplified one

class Answer(models.Model):

    question = models.ForeignKey(Question, related_name="answers")
    response = models.ForeignKey(Response, related_name="answers")
    body = models.TextField(blank=True, null=True)

无法自动创建迁移,它会删除数据库中的所有旧答案。我已经阅读了Schema Editor documentation但似乎并没有将模型迁移到已存在的模型。所以我想创建自己的操作,将AnswerTextAnswerInteger保存为Answer,然后删除AnswerTextAnswerInteger。我希望我不必直接编写SQL,但也许这是唯一的解决方案?我的迁移文件如下所示。我创建了一个名为MigrateAnswer的操作:

from myapp.migrations import MigrateAnswer


class Migration(migrations.Migration):

    operations = [
        migrations.RenameModel("AnswerBase", "Answer"),
        migrations.AddField(
            model_name='answer',
            name='body',
            field=models.TextField(blank=True, null=True),
        ),
        MigrateAnswer("AnswerInteger"),
        MigrateAnswer("AnswerText"),
        migrations.DeleteModel(name='AnswerInteger',),
        migrations.DeleteModel(name='AnswerText',),
    ]

所以我想在MigrateAnswer中做的是将旧模型(AnswerIntegerAnswerText)的值迁移到基类(现在命名为Answer,previousely {{1 }})。这是我的操作类:

AnswerBase

所以我的问题是:是否可以使用“执行”(即:不编写SQL)来执行此操作。如果是这样,我应该在我的操作的for循环中做什么?

提前致谢!

2 个答案:

答案 0 :(得分:2)

无需编写Operations类;数据迁移可以通过RunPython调用完成,如the docs所示。

在该函数中,您可以使用完全正常的模型实例方法;既然你知道要移动数据的字段,就不需要通过元查找来获取它们。

但是,您需要暂时以不同的名称调用新的body字段,因此它不会与子类上的旧字段冲突;您可以在最后重命名它并删除子类,因为该值将在基类中。

<section class="about" id="ABOUT">
  <div class="about-sidebox l">demo left
  </div>
  <div class="about-mainbox">demo
  </div>
  <div class="about-sidebox r">demo right
  </div>
</section>

答案 1 :(得分:0)

您可以为要进行这些修改的应用创建一个空迁移,并使用migrations.RunPython类来执行自定义python函数。

  1. 在这些功能中,您可以访问模型
  2. 您可以进行数据操作的Django ORM。
  3. 纯python,没有原始SQL。