Django`squashmigrations`留下了很多RemoveField

问题描述 投票:0回答:1

经过多年的积累,我正在尝试使用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)

django django-migrations
1个回答
0
投票

我想这是由于他们的优化器是如何实现的

您的迁移包含三个操作

  • 创建模型
  • 添加字段
  • 删除字段

优化器运行时

    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
  • 删除要压缩的迁移(0107 到 0121)并再次按
    makemigrations data
    生成新的集合。
  • 正常迁移

或者进行一些手工工作

    首先
  • squashmigrations data 0107 0121
  • 将压缩的迁移转换为正常迁移(doc),意思是
    • 删除
      replace
      属性
    • 更新其他迁移文件的
      dependencies
      属性,以不使用原始未压缩的迁移(0107 至 0121)文件
    • 删除替换的原始迁移
  • squashmigrations data 0104 0107_squash_0121

取决于您的动机,正如其他评论指出的那样,整个手动迁移文件的争论可能不值得

压制移民还有其他一些不明显的担忧。我在这里写了一张纸条

© www.soinside.com 2019 - 2024. All rights reserved.