【问题标题】:Django - alter bases in migrationsDjango - 在迁移中改变基地
【发布时间】:2016-08-27 07:46:31
【问题描述】:

出于某些原因,我想对我的模型进行重大更改。我想以某种方式重新设计我的整个设计,但是 Django 迁移实现通过不更新我的模型库来记住以前的设计。

让我快速展示一下我之前拥有的东西我现在拥有的东西。

app1.TopLevel
  |_ app1.IntermediateLevel
    |_ app2.LowLevel

我有 3 个这样的模型,然后现在我想把这个设计剪成更适合我当前项目的东西,比如

app2.TopLevel
  |_ app2.LowLevel

我的主要变化是,首先我不再需要中间模型,其次我不需要顶部保持 app1.TopLevel 那样。

我的数据没有问题(我运行了多次迁移,其中一些使用 Python 将数据放入临时字段,然后稍后将数据放回正确的字段并删除这些临时字段)。

我的问题是,当我们创建一个继承模型时,我们定义了它的基础;

migrations.CreateModel(
        name='IntermediateLevel',
        fields=[
            ('toplevel_ptr', models.OneToOneField(
                 auto_created=True,
                 on_delete=django.db.models.deletion.CASCADE,
                 parent_link=True,
                 primary_key=True, 
                 serialize=False, 
                 to='app1.TopLevel'),
            )
        ],
        bases=('app1.TopLevel',),
    )

在那种情况下,我会得到类似的东西

“LowLevel”类中的本地字段“toplevel_ptr”与基类“IntermediateLevel”中名称相似的字段发生冲突`

我阅读了官方文档和源代码(用于迁移),但到目前为止我还没有看到任何关于它的信息。是否可以告诉迁移系统我们更改了模型库(其父级)?

否则,我得到的唯一解决方案就是创建新模型,运行 python 迁移以将数据从旧模型复制到新模型。然后删除旧模型并重命名新模型以获得我想要的名称。

【问题讨论】:

  • 尝试使用链接到新基类的新的一对一字段来更改字段。
  • @mille_a 我现在遇到同样的问题!在过去的 4 天里一直在处理它,但无法弄清楚。当我尝试完全删除类似于您的 IntermediateLevel 模型的 UpperLevelModel 时,我收到 Invalid Bases 错误。我们能解决您的问题吗?请帮忙
  • 这个问题与你的情况有关吗@mille_a stackoverflow.com/questions/16487977/… ?
  • 最终我发现正确执行此操作的唯一方法是: * 以临时名称创建新模型 * 将数据从以前的模型迁移到新模型 * 删除以前的模型 * 重命名新模型所以你需要新的多次迁移来做到这一点

标签: django


【解决方案1】:

bases 遇到了同样的问题,我最终编写了自己的迁移操作,如下所示。不过值得一提的是,整个流程如下:

  1. 使用null=True 向模型添加新的IntegerField
  2. 将数据从xxx_ptr 复制到新字段
  3. 删除xxx_ptr字段
  4. 运行RemoveModelBasesOptions 操作
  5. 将临时 Integer 字段重命名为 id 并将其更改为 AutoField
  6. 删除我继承的旧模型

需要注意的一点是,如果您的模型中有 ForeignKey 的模型,无论如何它都会保留链接,所以它是安全的。

class RemoveModelBasesOptions(ModelOptionOperation):
    def __init__(self, name):
        super().__init__(name)

    def deconstruct(self):
        kwargs = {
            'name': self.name,
        }
        return (
            self.__class__.__qualname__,
            [],
            kwargs
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name_lower]
        model_state.bases = (models.Model,)
        state.reload_model(app_label, self.name_lower, delay=True)

    def database_forwards(self, app_label, schema_editor, from_state,
                          to_state):
        pass

    def database_backwards(self, app_label, schema_editor, from_state,
                           to_state):
        pass

    def describe(self):
        return "Remove bases from the model %s" % self.name

    @property
    def migration_name_fragment(self):
        return 'remove_%s_bases' % self.name_lower

然后,只需将其作为迁移中的操作调用:

class Migration(migrations.Migration):
    dependencies = [
        ('xxxx', '0025_xxxx'),
    ]

    operations = [
        RemoveModelBasesOptions('Foo')
    ]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 2015-08-03
    • 2021-02-06
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多