2015-10-06 2 views
0

Я перемещаю поле some_field от Model_A к новому Model_B с отношениями OneToOne. Прежде чем удалять это поле в Model_A, я хочу скопировать значение из (исторического) Model_A в созданный Model_B. Проблема в том, что я не могу получить поле во время миграции, поскольку Model_A больше не содержит some_field.Проблемы с доступом к полям модели Django от модели до миграции

Это сообщение об ошибке я получаю, когда я пытаюсь продолжить свою кодовую миграцию:

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, а второй удаляет поле some_field из Model_A?

ответ

1

Да, у вас должно быть историческое представление Model_A, и его довольно легко получить. То, что apps перешло в вашу функцию, вызванное RunPython миграция для, так почему вы используете некоторые apps2 insdead приложений здесь? Кроме того, вы должны получить свой 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 так или иначе? И что это?

+0

Кажется, я забыл изменить обратно от одного из предыдущих попыток меня с этим импортом: из django.apps импорта приложений, как apps2 К сожалению, удаление, что импорт и работает apps.get_model() не решает проблему , Вместо этого это приводит к следующей ошибке: ValueError: Невозможно назначить «»: «Model_B.model_a» должен быть экземпляром «Model_A». –

+1

Ваш 'Model_B' должен быть выбран с использованием тех же' приложений', что и 'Model_A', см. Обновленный ответ. – GwynBleidD

+0

GwynBleidD, вы заслуживаете медали! Все прошло гладко, когда я набрал новые модели так же, как Model_A. Каким-то образом я подумал, что было бы хорошо их смешивать. Очевидно, я был неправ! :) –