0

我注意到,我需要一个基于指定模型的通用模型,下面的例子应该说明我的意思:

前:

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)

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

4

1 回答 1

0

The following answer is based on this answer(https://stackoverflow.com/a/44148102/4129587)

In order to achieve that it is necessary to do a manual Data Migration

The following 5 basic migration steps lead to the desired result:

  1. create the new model TypingResult
  2. create a new foreign key that is nullable to the new model TypingResult in the old model TextResult
  3. copy all the old attributes to a new instance of the new model TypingResult
  4. remove the old attributes including the id from the original model
  5. alter the foreign key as the new primary key

It might be possible to start the migration with an autogenerated migration of the new models

The following code is based on an automatically generated migration and already tested

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'),
        ),
    ]
于 2017-05-25T01:15:54.490 回答