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

时间:2016-06-24 23:39:57

标签: python django

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

因此,我们发现需要采取三个不同的步骤:

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

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

    Foo

    将数据迁移作为迁移中的几个操作之一运行是否安全?我担心会出现任何类型的锁定,或者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 ), ] 传递给RunPython的app注册表是否与前面的操作不一致?

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

1 个答案:

答案 0 :(得分:6)

关于Django本身,这是非常安全的。每个操作将根据同一迁移中的所有先前迁移和操作接收正确的状态。您的RunPython操作将收到一个包含新Bar模型的应用注册表,但仍有Foo上的旧字段。

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

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