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()
请注意,
foo
的
AnotherModel
字段名称没有更改,但是关系已更新为
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:
- 创建 与 旧模型 相同的 模型
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
...
class Bar(model.Model):
...
-
切换代码以仅与新模型
Bar
使用。 (包括架构上的所有关系)
在迁移中,准备
RunPython
,它将数据从Foo复制到Bar(包括Foo的
id
)
- 可选的优化(如果需要更大的表)
提交B :( 不要着急,整个团队迁移后都要做)
-
老型号
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
,然后进行迁移。
之后,检查代码中是否有其他引用(模型类名称,相关(查询)名称,变量名称)。
如果需要,请进行迁移。
然后,有选择地将所有这些迁移合并为一个(确保也复制导入)。