Почему моя миграция данных Django с поля ForeignKey на OneToOneField не работает?

У меня есть несколько моделей с полем ForeignKey, которое указывает на другую модель:

class Specimen(models.Model):
   ...

class ResultA(models.Model):
   specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, ...)
   ...

class ResultB(models.Model):
   specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, ...)
   ...

В какой-то момент я понял, что каждый образец будет иметь только ноль или один результат каждого типа, так что, вероятно, имеет смысл превратить это в OneToOneField.

План заключается в следующем:

  1. Создайте дополнительное поле specimen_new, которое будет OneToOneField на каждом результате
  2. Создайте миграцию данных, которая переместит данные из поля ForeignKey в поле OneToOneField
  3. Удалите поле ForeignKey
  4. Переименуйте новое specimen_new OneToOneField в просто specimen
  5. Обновите все ссылки на код, чтобы правильно использовать новый OneToOneField

Шаг 1 был довольно простым:

class Specimen(models.Model):
   ...

class ResultA(models.Model):
   specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, ...)
   specimen_new = models.OneToOneField(Specimen, on_delete=models.CASCADE, ...)
   ...

class ResultB(models.Model):
   specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, ...)
   specimen_new = models.OneToOneField(Specimen, on_delete=models.CASCADE, ...)
   ...

Я застрял на шаге 2 - создание миграции данных.

Сейчас это выглядит следующим образом:

from django.db import migrations

def migrate_results(apps, schema_editor):
    # Get the model
    Specimen = apps.get_model('ahs', 'Specimen')

    # Update every specimen
    for specimen in Specimen.objects.filter():
        for field in Specimen._meta.get_fields():
            # Look for fields that end with "_new"
            if field.name.endswith("_new"):
                old_field_name = field.name[:-4] # Without the suffix
                new_field_name = field.name

                # Try to get the result
                result = getattr(specimen, old_field_name).first()

                # If the field had a result, copy it to the new OneToOneField
                if result:
                    setattr(specimen, new_field_name, result)
                    specimen.save()

class Migration(migrations.Migration):

    dependencies = [
        ('ahs', '0009_auto_20220525_0827'),
    ]

    operations = [
        migrations.RunPython(migrate_results),
    ]

Насколько я могу судить, это должно работать, и это не приводит к сбоям. Операторы печати в миграции (не показаны выше) показывают, что данные копируются. Но когда я запускаю миграцию, ни один из данных не был скопирован в OneToOneField.

Есть ли что-то, что я явно делаю неправильно?

Вернуться на верх