经过多年的积累,我正在尝试使用Django
manage.py squashmigrations
来减少迁移文件的数量和迁移操作。
Django 应该优化迁移,并且在某种程度上做到了这一点。 其他情况下,应该是明显的优化,但会被忽略,例如下面一个简单的
AddField
+RemoveField
字段就不是。 只有 AddField
内联到 CreateModel
中,但 RemoveField
仍然保留,而不是完全忽略 CreateModel
中的字段。
理想情况下,如果我没记错的话,南瓜之后不应该留下任何
RemoveField
。
迁移1:添加模型
class Migration(migrations.Migration):
dependencies = [("data", "0104")]
operations = [
migrations.CreateModel(
name="MyModel",
fields=[... ]
)
]
迁移2:向模型添加字段
class Migration(migrations.Migration):
dependencies = [("data", "0107")]
operations = [
migrations.AddField(
model_name="mymodel",
name="process_name",
field=models.CharField(default=None, max_length=300, null=True),
),
]
迁移3:从模型中删除相同的字段
class Migration(migrations.Migration):
dependencies = [("data", "0121")]
operations = [migrations.RemoveField(model_name="mymodel", name="process_name")]
导致迁移被挤压:
class Migration(migrations.Migration):
replaces = [...]
initial = True
operations = [
migrations.CreateModel(
name="MyModel",
fields=[
(
"process_name", # Should be possible to leave out ???
models.CharField(default=None, max_length=300, null=True),
),
],
),
migrations.RemoveField(model_name="mymodel", name="process_name"), # ???
]
这是预期的结果还是可能导致这种情况的原因?
我没有使用任何高级迁移功能,例如
RunSql
或 RunPython
。没有其他表或迁移依赖于 process_name
字段。
有什么办法可以给
squashmigrations
提示吗? 我可以再次运行南瓜以进一步优化吗?
(Django 版本 5.1)
我想这是由于他们的优化器是如何实现的。
您的迁移包含三个操作
优化器运行时
for i, operation in enumerate(operations): right = True # Should we reduce on the right or on the left. # Compare it to each operation after it for j, other in enumerate(operations[i + 1 :]): result = operation.reduce(other, app_label) ....
迭代从
i=0, operation=CreateModel
开始,并寻找任何可以 .reduce 的内容
j=0, other=AddField
是可简化的,因此它被整合到一个操作中
if isinstance(operation, AddField): return [ CreateModel( self.name, fields=self.fields + [(operation.name, operation.field)], options=self.options, bases=self.bases, managers=self.managers, ), ]
在
i=0
迭代期间,j=1, other=RemoveField
不可约简,因为 process_name
操作中不存在字段 i=0, operation=CreateModel
。
在第二次迭代期间,
i=1, operation=AddField
看起来确实可以通过RemoveField
进行优化,但我猜优化器并未选择优化操作
if isinstance(result, list): in_between = operations[i + 1 : i + j + 1] if right: new_operations.extend(in_between) new_operations.extend(result) elif all(op.reduce(other, app_label) is True for op in in_between): # Perform a left reduction if all of the in-between # operations can optimize through other. new_operations.extend(result) new_operations.extend(in_between) else: # Otherwise keep trying. new_operations.append(operation) break new_operations.extend(operations[i + j + 2 :]) return new_operations
我只是粗略地查看了源代码,因此很可能错误地解释了内容。
如果您的迁移历史很简单并且所有机器(生产/开发/等)都在您的控制之下。可能就足够了
migrate data 0103
makemigrations data
生成新的集合。或者进行一些手工工作
squashmigrations data 0107 0121
replace
属性dependencies
属性,以不使用原始未压缩的迁移(0107 至 0121)文件squashmigrations data 0104 0107_squash_0121
取决于您的动机,正如其他评论指出的那样,整个手动迁移文件的争论可能不值得