我正在处理我认为是一个常见问题:我已经意识到模型Foo
的现有模型字段会更好,作为一个完全独立的模型Bar
,其外键为{ {1}}。因此,我们需要进行架构迁移。但更重要的是,由于Foo
的模型字段中已存在数据,因此我们需要在删除该字段之前进行数据迁移。
因此,我们发现需要采取三个不同的步骤:
Foo
Bar
中的现有数据迁移到新表Foo
Bar
首先,我在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_migration
和CreateModel
,第二个用于AddField
,最后一个用于RunPython
。问题是它是否在功能上等同于在单个迁移中执行所有四个步骤(这提供了使整个迁移更容易理解的额外好处。)
答案 0 :(得分:6)
关于Django本身,这是非常安全的。每个操作将根据同一迁移中的所有先前迁移和操作接收正确的状态。您的RunPython
操作将收到一个包含新Bar
模型的应用注册表,但仍有Foo
上的旧字段。
可能不安全的是操作的数据库端。如果数据库在事务中支持DDL(数据定义语言),Django将在单个事务中运行完整的迁移。例如,PostgreSQL在事务中支持DDL,但不允许您在同一事务中混合模式更改和数据更改。尝试在单个迁移/事务中执行这两个操作都将导致错误。
如果您使用MySQL或Oracle,它们不支持DDL事务并且只在事务中运行RunPython
操作,则可以安全地将所有操作放在同一个迁移中。但是,您将失去一些跨数据库兼容性。