python - migrate无效 - 用于重命名模型和关系字段的Django迁移策略




django重置数据库 (8)

我打算在现有的Django项目中重命名几个模型,在该项目中,还有许多其他模型与要重命名的模型具有外键关系。 我相当确定这将需要多次迁移,但是我不确定确切的过程。

假设我从Django应用程序 myapp 的以下模型开始:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

我想重命名 Foo 模型,因为该名称实际上没有任何意义,并且会导致代码混乱,而 Bar 可以使名称更清晰。

根据我在Django开发文档中阅读的内容,我假设采用以下迁移策略:

第1步

修改 models.py

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()

请注意, fooAnotherModel 字段名称没有更改,但是关系已更新为 Bar 模型。 我的理由是,我不应该一次更改太多,并且如果将该字段名称更改为 bar ,则可能会丢失该列中的数据。

第2步

创建一个空迁移:

python manage.py makemigrations --empty myapp

第三步

在步骤2中创建的迁移文件中编辑 Migration 类,以将 RenameModel 操作添加到操作列表中:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

第四步

应用迁移:

python manage.py migrate

第5步

编辑 models.py 的相关字段名称:

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

第6步

创建另一个空迁移:

python manage.py makemigrations --empty myapp

步骤7

在步骤6中创建的迁移文件中编辑 Migration 类,以将任何相关字段名称的 RenameField 操作添加到操作列表中:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

步骤8

应用第二次迁移:

python manage.py migrate

除了更新其余代码(视图,表单等)以反映新的变量名之外,这基本上是新迁移功能如何工作的吗?

另外,这似乎需要很多步骤。 迁移操作可以某种方式压缩吗?

谢谢!


不幸的是,我发现了重命名迁移的问题(每个django 1.x),这些问题将旧表名保留在数据库中。

Django甚至没有在旧表上尝试任何操作,只是重命名了自己的模型。 外键和索引通常存在相同的问题-Django无法正确跟踪那里的更改。

最简单的解决方案(解决方法):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only

真正的解决方案(一种在2次提交中切换所有索引,约束,触发器,名称等的简便方法,但是对于 较小的 表而言):

提交A:

  1. 创建 旧模型 相同的 模型
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. 切换代码以仅与新模型 Bar 使用。 (包括架构上的所有关系)

在迁移中,准备 RunPython ,它将数据从Foo复制到Bar(包括Foo的 id

  1. 可选的优化(如果需要更大的表)

提交B :( 不要着急,整个团队迁移后都要做)

  1. 老型号 Foo 安全降落

进一步清理:

  • 壁球迁徙

Django中的错误:


只是想确认并添加ceasaro评论。 Django 2.0现在似乎可以自动执行此操作。

我使用的是Jango 2.2.1,我要做的全部工作就是重命名模型并运行makemigrations。

在这里,它询问我是否已将特定的类从A重命名为B,我选择了yes,然后进行了迁移,并且一切似乎都正常。

注意我没有在project / migrations文件夹内的任何文件中重命名旧模型名称。


在他对这个 answer 评论中,我会用@ceasaro来形容。

较新版本的Django可以检测到更改并询问已完成的操作。 我还要补充一点,Django可能会混合一些迁移命令的执行顺序。

进行一些小的更改并运行 makemigrations 并进行 migrate 是明智的,如果发生错误,则可以编辑迁移文件。

某些行的执行顺序可以更改,以免出错。


如果您使用的是像PyCharm这样的优秀IDE,则可以右键单击模型名称并进行重构->重命名。 这免除了您遍历引用该模型的所有代码的麻烦。 然后运行makemigrations并进行迁移。 Django 2+只会确认名称更改。


我也遇到了v.thorey所描述的问题,发现他的方法非常有用,但可以凝结为更少的步骤,实际上是步骤5至8,如Fiver所描述的,而没有步骤1-4,只是步骤7是我所需要的。在步骤3下方。总体步骤如下:

步骤1:在models.py中编辑相关字段名称

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

步骤2:建立一个空的迁移

python manage.py makemigrations --empty myapp

步骤3:在步骤2中创建的迁移文件中编辑Migration类

class Migration(migrations.Migration):

dependencies = [
    ('myapp', '0001_initial'), 
]

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]

步骤4:套用迁移

python manage.py migrate

完成

PS我已经在Django 1.9上尝试过这种方法


我将Django从版本10升级到版本11:

sudo pip install -U Django

-U 表示“升级”),它解决了该问题。


我需要做同样的事情。 我一次更改了模型(即同时进行了步骤1和步骤5)。 然后创建模式迁移,但将其编辑为:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

这工作得很好。 显示了我所有的现有数据,其他所有表均引用了Bar fine。

从这里开始: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/ : https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/


我需要重命名几个表。 但是Django仅注意到一种模型重命名。 发生这种情况是因为Django反复遍历添加的模型,然后删除了模型。 对于每对,它会检查它们是否属于同一应用,并且具有 相同的字段 。 只有一个表没有要重命名的表的外键(您记得,外键包含模型类名称)。 换句话说,只有一个表没有字段更改。 这就是为什么它被注意到。

因此,解决方案是一次重命名一个表,更改 models.py 模型类名称,可能是 views.py ,然后进行迁移。 之后,检查代码中是否有其他引用(模型类名称,相关(查询)名称,变量名称)。 如果需要,请进行迁移。 然后,有选择地将所有这些迁移合并为一个(确保也复制导入)。





django-migrations