在迁移之前从模型访问Django模型字段时出现问题

时间:2015-10-06 21:03:23

标签: django django-models django-migrations

我正在将some_field字段从Model_A移动到具有OneToOne关系的新Model_B。在Model_A中删除此字段之前,我想将(历史)Model_A中的值复制到新创建的Model_B。问题是我无法在迁移时检索字段,因为Model_A不再包含some_field

这是我尝试运行自定义迁移时收到的错误消息:

AttributeError: 'Model_A' object has no attribute 'some_field'

更改前的模型:

class Model_A:
    some_field = models.BooleanField(default=False)
    some_other_field = models.BooleanField(default=False)

更改后的模型:

class Model_A:
    some_other_field = models.BooleanField(default=False)

class Model_B:
    model_a = models.OneToOneField(Model_A, related_name='extension')
    some_field = models.BooleanField(default=False)

迁移:

class Migration(migrations.Migration):

    dependencies = [
        ('my_app', '0001_initial'),
    ]

    def forwards_func(apps, schema_editor):
        # This is where I try to get the "historical" Model_A
        Model_A = apps2.get_model("my_app", "Model_A")

        # And this is where I intend to copy the some_field values
        for model_A_instance in Model_A.objects.all():
            b = Model_B(model_a=model_A_instance)
            # b gets created correctly, but the following step fails
            b.some_field = modelA_instance.some_field
            b.save()

    operations = [
        migrations.CreateModel(
            name='Model_B',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('some_field', models.BooleanField(default=False)),
                ('model_a', models.OneToOneField(related_name='extension', to='my_app.Model_A')),
            ],
            options={
            },
            bases=(models.Model,),
        ),

        migrations.RunPython(forwards_func),

        migrations.RemoveField(
            model_name='model_a',
            name='some_field',
        ),
    ]

我非常清楚我不得不抓住Model_A(当前在数据库中的那个)的“历史”表示,但我认为这就是apps2.get_model("my_app", "Model_A")部分是为了。

有关如何完成此操作的任何输入?或者我应该将迁移分成两部分,第一部分创建Model_B +复制some_field值,第二部分删除Model_A中的some_field字段?

1 个答案:

答案 0 :(得分:2)

是的,您需要拥有Model_A的历史记录,并且检索它非常容易。那就是apps传递给RunPython迁移所调用的函数的原因是什么,为什么你在这里使用了一些apps2 insdead应用程序?此外,您应该从[{1}}实例Model_B获取apps来自Model_A的实例。您的迁移应该如下所示:

class Migration(migrations.Migration):

    dependencies = [
        ('my_app', '0001_initial'),
    ]

    def forwards_func(apps, schema_editor):
        # This is where I try to get the "historical" Model_A
        # here is change - using apps passed into forwards_func by RunPython instead of apps2
        Model_A = apps.get_model("my_app", "Model_A")
        Model_B = apps.get_model("my_app", "Model_B")

        # And this is where I intend to copy the some_field values
        for model_A_instance in Model_A.objects.all():
            b = Model_B(model_a=model_A_instance)
            b.some_field = modelA_instance.some_field
            b.save()

    operations = [
        migrations.CreateModel(
            name='Model_B',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('some_field', models.BooleanField(default=False)),
                ('model_a', models.OneToOneField(related_name='extension', to='my_app.Model_A')),
            ],
            options={
            },
            bases=(models.Model,),
        ),

        migrations.RunPython(forwards_func),

        migrations.RemoveField(
            model_name='model_a',
            name='some_field',
        ),
    ]

为什么你还在使用apps2?它是什么?