Правильно ли я написал миграцию данных для изменения типа данных?

Допустим, у меня есть модель TestModel:

class TestModel(models.Model):
    field1 = models.CharField(max_length=255)
    field2 = models.IntegerField()

    def __str__(self):
        return f"{self.field1}"

Но теперь мне нужно изменить тип поля2 на Text. Чтобы не потерять данные в модели TestModel, мне нужно написать миграцию данных.

Поэтому я создаю новую модель NewTestModel:

class NewTestModel(models.Model):
    field1 = models.CharField(max_length=255)
    field2 = models.TextField()

    def __str__(self):
        return f"{self.field1}"

Выполнить python manage.py makemigrations команду

В файле миграции 0006_newtestmodel.py я добавляю функцию copy_data и запускаю ее с помощью migrations.RunPython(copy_data)

from django.db import migrations, models

def copy_data(apps, database_schema):
    TestModel = apps.get_model("data_migrations", "TestModel")
    NewTestModel = apps.get_model("data_migrations", "NewTestModel")

    for old_object in TestModel.objects.all():
        new_object = NewTestModel(
            field1 = old_object.field1,
            field2 = old_object.field2
        )
        new_object.save()


class Migration(migrations.Migration):

    dependencies = [
        ('data_migrations', '0005_testmodel'),
    ]

    operations = [
        migrations.CreateModel(
            name='NewTestModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('field1', models.CharField(max_length=255)),
                ('field2', models.TextField()),
            ],
        ),
        migrations.RunPython(copy_data)
    ]

Затем я удаляю модель TestModel и запускаю команды миграции.

После этого я переименовываю NewTestModel в TestModel и снова запускаю команды миграции.

Все получилось так, как и должно было получиться.

Правильно ли я все сделал?

Правильно ли я все сделал?

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

Мы можем копировать оптом с помощью:

def copy_data(apps, database_schema):
    TestModel = apps.get_model('data_migrations', 'TestModel')
    NewTestModel = apps.get_model('data_migrations', 'NewTestModel')

    NewTestModel.objects.bulk_create(
        [
            NewTestModel(field1=old_object.field1, field2=old_object.field2)
            for old_object in TestModel.objects.all()
        ]
    )
Вернуться на верх