【问题标题】:Problems accessing Django model fields from model before migration迁移前从模型访问 Django 模型字段的问题
【发布时间】:2016-01-03 22:40:52
【问题描述】:

我正在将字段 some_fieldModel_A 移动到新的 Model_B,并具有 OneToOne 关系。在删除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 字段?

【问题讨论】:

    标签: django django-models django-migrations


    【解决方案1】:

    是的,您需要有Model_A 的历史表示,并且很容易检索它。这就是apps 传递给RunPython 迁移调用的函数的目的,那么为什么你在这里使用一些apps2 insdead 的应用程序呢?此外,您应该从与 Model_A 相同的 apps 实例中获取您的 Model_B。您的迁移应如下所示:

    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?它是什么?

    【讨论】:

    • 似乎我忘记从我之前的一次导入尝试中改回来:from django.apps import apps as apps2 不幸的是,删除该导入并运行 apps.get_model() 并不能解决问题。它给了我以下错误:ValueError:无法分配“”:“Model_B.model_a”必须是“Model_A”实例。
    • 您的Model_B 应该使用与apps 相同的Model_A 获取,请参阅更新后的答案。
    • GwynBleidD,你应该得到一枚奖牌!当我以与 Model_A 相同的方式获取新模型时,一切都很顺利。不知何故,我认为混合它们是可以的。显然,我错了! :)
    • 您应该永远models.py 或迁移中的其他来源导入模型。始终依赖 apps 传递给您的自定义迁移函数。
    猜你喜欢
    • 2015-02-03
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    相关资源
    最近更新 更多