2017-05-25 48 views
0

我已经注意到了,我需要根据特定的模型的通用模式,下面的例子应该说明我的意思:Django的:外包与继承模型性能更一般的模型

前:

class TextResult(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1) 
    text = models.ForeignKey(Text) 
    wpm = models.FloatField(default=0.0) 
    accuracy = models.FloatField(default=1.0) 

后:

class TypingResult(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1) 
    wpm = models.FloatField(default=0.0) 
    accuracy = models.FloatField(default=1.0) 


class TextResult(TypingResult): 
    text = models.ForeignKey(Text) 

虽然已经有在原有模型的一些数据,所以需要将数据迁移到新的modelstructure

回答

0

以下的答案是基于此答案(https://stackoverflow.com/a/44148102/4129587

为了实现它,必须执行手动数据迁移

以下5个基本的迁移步骤导致所希望的结果:

  1. 创建新模式TypingResult
  2. 创建一个新的外键可为空的新模式TypingResult在旧模式TextResult
  3. 所有旧的属性复制到新的模式TypingResult
  4. 删除旧的属性,包括从最初的模型
  5. 的ID改变外键为新的主键

的新实例使用新模型的自动生成迁移开始迁移可能是可能的

以下代码基于自动生成的迁移并已经过测试

from __future__ import unicode_literals 

from django.conf import settings 
import django.core.validators 
from django.db import migrations, models 
import django.db.models.deletion 

def copy_text_results_to_typing_results(apps, schema_editor): 
    TypingResult = apps.get_model('testapp', 'TypingResult') 
    TextResult = apps.get_model('testapp', 'TextResult') 
    for text_result in TextResult.objects.all(): 
     copied_result = TypingResult() 
     copied_result.user = text_result.user 
     copied_result.wpm = text_result.wpm 
     copied_result.accuracy = text_result.accuracy 
     copied_result.save() 
     text_result.typingresult_ptr = copied_result 
     text_result.save() 

class Migration(migrations.Migration): 

    dependencies = [ 
     migrations.swappable_dependency(settings.AUTH_USER_MODEL), 
     ('testapp', '0001_initial'), 
    ] 

    operations = [ 
     migrations.CreateModel(
      name='TypingResult', 
      fields=[ 
       ('id', models.AutoField(auto_created=True, 
             primary_key=True, 
             serialize=False, 
             verbose_name='ID')), 
       ('wpm', models.FloatField(default=0.0)), 
       ('accuracy', models.FloatField(default=1.0)), 
       ('user', models.ForeignKey(default=1, 
              on_delete=django.db.models.deletion.CASCADE, 
              to=settings.AUTH_USER_MODEL)), 
      ], 
     ), 
     # add the foreign key for the new inherited model, 
     # it is allowed to have null values since the actual values have to be 
     # copied first to this, it will be changed later 
     migrations.AddField(
      model_name='textresult', 
      name='typingresult_ptr', 
      field=models.OneToOneField(blank=True, null=True, to='testapp.TypingResult'), 
     ), 
     # copy the old values to the new inherited model 
     migrations.RunPython(copy_text_results_to_typing_results), 
     # remove the old id and the copied fields from the TextResult model 
     migrations.RemoveField(
      model_name='textresult', 
      name='accuracy', 
     ), 
     migrations.RemoveField(
      model_name='textresult', 
      name='id', 
     ), 
     migrations.RemoveField(
      model_name='textresult', 
      name='user', 
     ), 
     migrations.RemoveField(
      model_name='textresult', 
      name='wpm', 
     ), 
     # alter the id of the inherited model to be the new primary key 
     migrations.AlterField(
      model_name='textresult', 
      name='typingresult_ptr', 
      field=models.OneToOneField(auto_created=True, 
             on_delete=django.db.models.deletion.CASCADE, 
             parent_link=True, 
             primary_key=True, 
             serialize=False, 
             to='testapp.TypingResult'), 
     ), 
    ]