Django模型和关联字段的重命名的迁移策略
Django模型和关联字段的重命名的迁移策略
我计划在一个已存在的Django项目中重命名几个模型,在这个项目中还有许多其他模型与我想要重命名的模型具有外键关系。我相当确定这将需要多个迁移,但我不确定具体的步骤。\n假设我从名为myapp
的Django应用程序开始,其中包含以下模型:\n
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()
\n我想重命名Foo
模型,因为名称实际上没有意义,并且在代码中引起了混淆,而Bar
将是一个更清晰的名称。\n根据我在Django开发文档中所读到的,我假设以下迁移策略:\n
步骤1
\n修改models.py
:\n
class Bar(models.Model): # <-- 更改模型名称 name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True) class AnotherModel(models.Model): foo = models.ForeignKey(Bar) # <-- 更改关系,但不更改字段名称 is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.ForeignKey(Bar) # <-- 更改关系,但不更改字段名称 is_ridonkulous = models.BooleanField()
\n注意AnotherModel
中foo
字段的名称不变,但关系更新为Bar
模型。我的理由是我不应该一次改变太多,如果我将此字段名称更改为bar
,我会有丢失该列数据的风险。\n
步骤2
\n创建一个空的迁移:\n
python manage.py makemigrations --empty myapp
\n
步骤3
\n编辑步骤2中创建的迁移文件中的Migration
类,将RenameModel
操作添加到操作列表中:\n
class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RenameModel('Foo', 'Bar') ]
\n
步骤4
\n应用迁移:\n
python manage.py migrate
\n
步骤5
\n编辑models.py
中的相关字段名称:\n
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) # <-- 更改字段名称 is_awesome = models.BooleanField() class YetAnotherModel(models.Model): bar = models.ForeignKey(Bar) # <-- 更改字段名称 is_ridonkulous = models.BooleanField()
\n
步骤6
\n创建另一个空的迁移:\n
python manage.py makemigrations --empty myapp
\n
步骤7
\n编辑步骤6中创建的迁移文件中的Migration
类,将RenameField
操作添加到操作列表中,以更改任何相关字段名称:\n
class Migration(migrations.Migration): dependencies = [ ('myapp', '0002_rename_fields'), # <-- 这样可以吗? ] operations = [ migrations.RenameField('AnotherModel', 'foo', 'bar'), migrations.RenameField('YetAnotherModel', 'foo', 'bar') ]
\n
步骤8
\n应用第二个迁移:\n
python manage.py migrate
\n
\n除了更新其余代码(视图、表单等)以反映新的变量名称外,这基本上是新的迁移功能的工作原理吗?\n此外,这看起来是一系列繁琐的步骤。迁移操作能否以某种方式简化?\n谢谢!
Django迁移策略:重命名模型和关联字段
在当前版本的Django中,您可以重命名模型并运行python manage.py makemigrations
命令,Django会询问您是否要重命名模型,如果选择是,那么所有的重命名过程都将自动完成。这确实需要成为当前的首选答案,尽管以前的答案仍然有用和有趣。如今Django会自动为您完成这些操作。
问题的原因:
在旧版的Django中,重命名模型和关联字段是一个比较麻烦的过程,需要手动修改数据库表结构和相关代码,容易引发错误和冲突。这给开发人员带来了很多麻烦和困惑。
解决方法:
在当前版本的Django中,重命名模型和关联字段变得非常简单。您只需运行python manage.py makemigrations
命令,并在提示时选择重命名模型。Django将自动进行重命名的过程,更新数据库表结构和相关代码,省去了手动修改的繁琐步骤。
这个新的迁移策略极大地简化了重命名模型和关联字段的过程,大大提高了开发效率和代码质量。开发人员不再需要手动修改数据库表结构和相关代码,减少了出错的可能性。
通过当前版本的Django迁移工具,我们可以轻松地重命名模型和关联字段,大大提高了开发效率和代码质量。这个新的迁移策略让开发人员不再需要手动修改数据库表结构和相关代码,使得重命名过程更加简单和可靠。使用这个策略,我们可以避免错误和冲突,更加轻松地进行模型和字段的重命名操作。
Django模型重命名和关联字段的迁移策略
在一开始,我以为Fiver的方法适用于我,因为在前四个步骤中,迁移工作得很好。然而,隐含的更改'ForeignKeyField(Foo)'到'ForeignKeyField(Bar)'在任何迁移中都没有关联。这就是为什么当我想要重命名关联字段(步骤5-8)时迁移失败的原因。
这可能是因为在我的情况下,'AnotherModel'和'YetAnotherModel'被分发到其他应用程序中。
所以我按照以下步骤成功地重命名了我的模型和关联字段:
我从这里适应了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()
步骤1:
将每个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
步骤2:(类似于Fiver的步骤2-4)
更改模型名称
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
步骤3:
将IntegerField()转换回先前的ForeignKeyField或OneToOneField,但使用新的Bar模型。(以前的整数字段存储了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->Bar迁移的依赖关系。
因此,如果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
步骤4:
最后,您可以重命名字段
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
就是这样!
这适用于Django 1.8
谢谢!这真的非常有帮助。不过请注意 - 我还必须手动重命名和/或删除PostgreSQL字段索引,因为在将Foo重命名为Bar后,我创建了一个名为Bar的新模型。
谢谢!我认为关键部分是将所有外键,无论是进入还是离开要重命名的模型,转换为IntegerField
。这对我非常完美地起作用,并且有一个额外的优点,它们以正确的名称重新创建。当然,我建议在实际运行之前审查所有迁移!
谢谢!我尝试了许多不同的策略来重命名一个其他模型有外键引用的模型(步骤1-3),这是唯一一个成功的方法。
将ForeignKey
改为IntegerField
救了我一天的工作!
Django模型和关联字段重命名的迁移策略
在使用Django进行模型和关联字段重命名时,可能会遇到一些问题。下面是一个解决方法:
1. 创建一个新的迁移文件,并设置依赖关系为之前的初始迁移文件。
2. 在操作中使用`migrations.RenameModel`来重命名模型。
3. 使用`migrations.RenameField`来重命名相关的字段。
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和旧的迁移文件),可能会出现一些错误。
更新:较新版本的Django通常能够检测到并询问模型是否被重命名。因此,可以先运行`manage.py makemigrations`命令,然后检查迁移文件。
谢谢答案。我已经使用我概述的步骤进行了迁移,但我想知道您是否尝试在现有数据上进行迁移,还是只在空数据库上进行了测试?
我在本地环境中使用sqlite数据库进行了测试,尽管只有几行数据(当我切换到生产环境时,我打算清空所有数据,包括迁移文件)。
如果在迁移文件中使用`apps.get_model`,则不需要更改模型名称。我花了很多时间才弄清楚这一点。
关于旧的迁移中的引用问题,可以查看Django文档(https://docs.djangoproject.com/en/1.8/topics/migrations/#considerations-when-removing-model-fields)的解释。可能会帮助避免将此迁移放入当前应用程序中,否则它将继续引起问题。
在Django 2.0中,如果您更改了模型名称,`./manage.py makemigrations myapp`命令会询问您是否重命名了模型。例如:"Did you rename the myapp.Foo model to Bar? [y/N]"。如果回答'y',则迁移文件将包含`migrations.RenameModel('Foo', 'Bar')`。对于重命名的字段也是如此。
`manage.py makemigrations myapp`可能仍然会失败:"You may have to manually add this if you change the model’s name and quite a few of its fields at once; to the autodetector, this will look like you deleted a model with the old name and added a new one with a different name, and the migration it creates will lose any data in the old table."(Django 2.1文档)。对我来说,只需创建一个空的迁移文件,将模型重命名添加到其中,然后像往常一样运行`makemigrations`即可。
补充说明:如果同时对模型进行了更改,Django可能无法自动检测到模型的重命名。为了解决此问题,可以将更改分为两个独立的迁移操作。首先重命名模型,运行`makemigrations`,然后进行模型更改,再次运行`makemigrations`。