我打算在现有的Django项目中重命名几个模型,其中有许多其他模型与我想要重命名的模型有外键关系。我很确定这需要多次迁移,但我不确定具体的过程。
假设我在名为myapp
的Django应用程序中开始使用以下模型:
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开发文档中的内容,我假设采用以下迁移策略:
修改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()
请注意AnotherModel
的{{1}}字段名称不会更改,但关系会更新为foo
模型。我的理由是我不应该立刻改变太多,如果我将此字段名称更改为Bar
,我可能会丢失该列中的数据。
创建空迁移:
bar
编辑在步骤2中创建的迁移文件中的python manage.py makemigrations --empty myapp
类,将Migration
操作添加到操作列表中:
RenameModel
应用迁移:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
在python manage.py migrate
中编辑相关的字段名称:
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
类,将任何相关字段名称的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')
]
除了更新代码的其余部分(视图,表单等)以反映新的变量名称之外,这基本上是新迁移功能的工作原理吗?
此外,这似乎是很多步骤。迁移操作能否以某种方式压缩?
谢谢!
答案 0 :(得分:103)
所以当我尝试这个时,似乎你可以压缩步骤3 - 7:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar'),
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
如果您不更新导入的名称,则可能会收到一些错误,例如: admin.py甚至更旧的迁移文件(!)。
更新:正如ceasaro所述,较新版本的Django通常能够检测并询问是否重命名了模型。因此,首先尝试manage.py makemigrations
,然后检查迁移文件。
答案 1 :(得分:29)
起初,我认为Fiver的方法对我有用,因为迁移工作到第4步。然而,隐式更改'ForeignKeyField(Foo)'到'ForeignKeyField(Bar)'在任何迁移中都没有关系。这就是当我想重命名关系字段时迁移失败的原因(步骤5-8)。 这可能是由于我的'AnotherModel'和'YetAnotherModel'在我的情况下在其他应用程序中调度的事实。
所以我设法重命名我的模型和关系字段,执行以下步骤:
我改编了this的方法,尤其是otranzer的伎俩。
就像Fiver一样,我们说我们有 myapp :
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
在 myotherapp :
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
将每个OneToOneField(Foo)或ForeignKeyField(Foo)转换为IntegerField()。 (这会将相关Foo对象的id保持为整数字段的值。)
class AnotherModel(models.Model):
foo = models.IntegerField()
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.IntegerField()
is_ridonkulous = models.BooleanField()
然后
python manage.py makemigrations
python manage.py migrate
更改型号名称
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
创建空迁移:
python manage.py makemigrations --empty myapp
然后编辑它:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
最终
python manage.py migrate
将IntegerField()转换回以前的ForeignKeyField或OneToOneField,但使用新的Bar Model。 (之前的整数字段存储了id,所以django理解并重新建立连接,这很酷。)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_ridonkulous = models.BooleanField()
然后做:
python manage.py makemigrations
非常重要的是,在此步骤中,您必须修改每个新的迁移并添加对RenameModel Foo的依赖关系。酒吧迁移。 因此,如果AnotherModel和YetAnotherModel都在myotherapp中,则myotherapp中创建的迁移必须如下所示:
class Migration(migrations.Migration):
dependencies = [
('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
]
operations = [
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')
),
]
然后
python manage.py migrate
最终您可以重命名字段
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_ridonkulous = models.BooleanField()
然后自动重命名
python manage.py makemigrations
(django应该问你是否真的重命名了模型名,说是)
python manage.py migrate
就是这样!
这适用于Django1.8
答案 2 :(得分:6)
我需要做同样的事情。我一下子改变了模型(即步骤1和步骤5一起)。然后创建了一个模式迁移,但将其编辑为:
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('Foo','Bar')
def backwards(self, orm):
db.rename_table('Bar','Foo')
这完美无缺。我现有的所有数据都显示出来,所有其他表格都标准为Bar。
从这里开始:https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
答案 3 :(得分:6)
对于Django 1.10,我设法通过简单地运行Makemigrations,然后迁移为应用程序来更改两个模型类名称(包括ForeignKey和数据)。对于Makemigrations步骤,我必须确认我想要更改表名。迁移更改了表的名称没有问题。
然后我更改了ForeignKey字段的名称以匹配,并且Makemigrations再次询问我确认我想要更改名称。迁移比做出改变。
所以我在没有任何特殊文件编辑的情况下分两步执行此操作。我之前确实收到了错误,因为我忘了更改admin.py文件,如@wasibigeek所述。
答案 4 :(得分:5)
我正在使用Django版本1.9.4
我已按照以下步骤操作: -
我刚将模型oldName重命名为NewName
运行python manage.py makemigrations
。它会问你
Did you rename the appname.oldName model to NewName? [y/N]
选择Y
运行python manage.py migrate
,它会要求您
以下内容类型陈旧且需要删除:
appname | oldName
appname | NewName
外键与这些内容类型相关的任何对象也会 被删除。您确定要删除这些内容类型吗? 如果您不确定,请回答'不'。
Type 'yes' to continue, or 'no' to cancel: Select No
它为我重命名并将所有现有数据迁移到新的命名表。
答案 5 :(得分:4)
我也遇到了v.thorey所描述的问题,并发现他的方法非常有用,但可以简化为更少的步骤,实际上是步骤5到8,正如Fiver所描述的,没有步骤1到4,除了步骤7需要是改为我的下面第3步。整体步骤如下:
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()
python manage.py makemigrations --empty myapp
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')
]
python manage.py migrate
P.S。我在Django 1.9上试过这种方法
答案 6 :(得分:2)
不幸的是,我发现了重命名迁移的问题(每个django 1.x),这会在db中留下旧的表名(甚至不要在旧表上尝试任何东西,只需重命名模型)。
该案例的解决方案:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
...
Bar = Foo
答案 7 :(得分:1)
我需要重命名几张桌子。但Django只注意到一个模型重命名。发生这种情况是因为Django迭代了添加的,然后删除的模型。对于每一对,它会检查他们是否属于同一个应用并拥有identical fields。只有一个表没有要重命名的表的外键(外键包含模型类名,如您所记得的)。换句话说,只有一个表没有字段更改。这就是它被注意到的原因。
因此,解决方案是一次重命名一个表,更改models.py
中的模型类名称,可能views.py
,并进行迁移。之后检查代码以获取其他引用(模型类名,相关(查询)名称,变量名)。如果需要,进行迁移。然后,可选地将所有这些迁移合并为一个(确保也复制导入)。
答案 8 :(得分:1)
在他对这个answer的评论中,我会用@ceasaro来表达。
较新版本的Django可以检测到更改并询问已完成的操作。 我还要补充一点,Django可能会混合一些迁移命令的执行顺序。
明智的做法是应用少量更改并运行makemigrations
和migrate
,如果发生错误,则可以编辑迁移文件。
某些行的执行顺序可以更改,以免出错。
答案 9 :(得分:1)
在当前版本的Django中,您可以重命名模型并运行python manage.py makemigrations
,然后django将询问您是否要重命名模型,如果您选择yes,则将自动完成所有重命名过程。
答案 10 :(得分:0)
如果您使用的是像PyCharm这样的优秀IDE,则可以右键单击模型名称并进行重构->重命名。这免除了您遍历引用该模型的所有代码的麻烦。然后运行makemigrations并进行迁移。 Django 2+只会确认名称更改。
答案 11 :(得分:0)
只想确认并添加ceasaro评论。 Django 2.0现在似乎可以自动执行此操作。
我使用的是Jango 2.2.1,我要做的全部工作就是重命名模型并运行makemigrations。
在这里询问我是否已将特定的类从A重命名为B,我选择是,然后进行迁移,一切似乎都正常。
请注意,我没有在project / migrations文件夹内的任何文件中重命名旧模型名称。
答案 12 :(得分:-7)
我将Django从版本10升级到版本11:
sudo pip install -U Django
(-U
代表“升级”)它解决了这个问题。