2017-05-25 80 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'), 
     ), 
    ]