在较大的Django迁移中只进行一次操作来进行数据迁移是否安全?

fil*_*d13 7 python django

我正在处理我认为是一个常见问题:我已经意识到模型的现有模型字段Foo将更好地作为Bar具有外键的完全单独的模型Foo.因此,我们需要进行架构迁移.但更重要的是,由于模型领域中已有数据Foo,我们需要在删除该字段之前进行数据迁移.

所以我们发现有三个不同的步骤:

  1. 创建新表 Bar
  2. 将现有数据迁移Foo到新表中Bar
  3. 删除现有字段 Foo

首先,我在models.py中进行所有必需的模型更改,然后自动生成迁移.一切看起来都不错,除了我们将丢失该字段中的所有数据,因此我需要添加一个额外的操作来处理数据迁移(RunPython).我最终会得到以下内容:

def do_data_migration(apps, schema_editor):
    # Migrate data from Foo to Bar

class Migration(migrations.Migration):

    dependencies = [ 
        ('exampleapp', 'migration_003'),
    ]   

    operations = [ 
        migrations.CreateModel(
            # Create the new model Bar
        ),  
        migrations.AddField(
            # Add the foreign key field to model Foo
        ),  
        migrations.RunPython(
            do_data_migration
        ),
        migrations.RemoveField(
            # Remove the old field from Foo
        ),  
    ]
Run Code Online (Sandbox Code Playgroud)

将数据迁移作为迁移中的几个操作之一运行是否安全?我担心的是,有任何类型的锁定正在进行,或者RunPython传递到的应用程序注册表是否do_data_migration与前面的操作不一致?

我知道我将能够创建三个迁移:一个用于CreateModelAddField,第二对RunPython,最后进行RemoveField.问题是它是否在功能上等同于在单个迁移中执行所有四个步骤(这提供了使整个迁移更容易理解的额外好处.)

knb*_*nbk 6

关于Django本身,这是绝对安全的。每个操作将基于先前的所有迁移以及同一迁移中的操作接收正确的状态。您的RunPython操作将收到一个应用程序注册表,其中包含新Bar模型,并且旧字段仍在上Foo

操作的数据库端可能并不安全。如果数据库在事务中支持DDL(数据定义语言),则Django将在单个事务中运行完整的迁移。例如,PostgreSQL在事务中支持DDL,但不允许您在同一事务中混合模式更改和数据更改。尝试在单个迁移/事务中同时执行这两项操作将导致错误。

如果使用不支持DDL事务并且仅RunPython在事务中运行该操作的MySQL或Oracle,则可以安全地将所有操作置于同一迁移中。但是,您将失去一些跨数据库兼容性。