【问题标题】:Django: outsource model properties with inheritance to a more general modelDjango:将具有继承性的模型属性外包给更通用的模型
【发布时间】:2017-05-25 01:13:39
【问题描述】:

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

之前:

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)

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

【问题讨论】:

    标签: python django model migration inherited


    【解决方案1】:

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

    为了实现这一点,有必要进行手动数据迁移

    以下 5 个基本迁移步骤可实现预期结果:

    1. 创建新模型TypingResult
    2. 在旧模型TextResult 中创建一个对新模型TypingResult 可以为空的新外键
    3. 将所有旧属性复制到新模型TypingResult的新实例中
    4. 从原始模型中删除包括 id 在内的旧属性
    5. 将外键更改为新的主键

    可以通过自动生成的新模型迁移来开始迁移

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

    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'),
            ),
        ]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-06
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 2014-06-17
      • 1970-01-01
      • 2011-12-09
      相关资源
      最近更新 更多