使用Django / South重命名模型最简单的方法是什么?
我一直在南方的网站上寻找答案,Google和SO,但找不到一个简单的方法来做到这一点。
我想使用South重命名一个Django模型。 假设你有以下几点:
class Foo(models.Model): name = models.CharField() class FooTwo(models.Model): name = models.CharField() foo = models.ForeignKey(Foo)
而你想把Foo转换成Bar,即
class Bar(models.Model): name = models.CharField() class FooTwo(models.Model): name = models.CharField() foo = models.ForeignKey(Bar)
为了简单FooTwo
,我只是FooTwo
名字从Foo
改成Bar
,但是现在忽略FooTwo
的foo
成员。
使用South最简单的方法是什么?
- 我可能可以做一个数据迁移,但似乎很相关。
- 写一个自定义的迁移,例如
db.rename_table('city_citystate', 'geo_citystate')
,但我不知道如何解决在这种情况下的外键。 - 一个更简单的方法,你知道吗?
要回答你的第一个问题,简单的模型/表重命名是非常简单的。 运行命令:
./manage.py schemamigration yourapp rename_foo_to_bar --empty
(更新2:尝试--auto
而不是--empty
以避免下面的警告。感谢@KFB的提示。)
如果您使用的是南部的旧版本,则需要startmigration
而不是模式schemamigration
。
然后手动编辑迁移文件,如下所示:
class Migration(SchemaMigration): def forwards(self, orm): db.rename_table('yourapp_foo', 'yourapp_bar') def backwards(self, orm): db.rename_table('yourapp_bar','yourapp_foo')
您可以使用模型类中的db_table
Meta选项更简单地完成此操作。 但是每当你这样做的时候,你就增加了你的代码库的遗留重量 – 类名与表名不一样会使你的代码更难理解和维护。 为了清楚起见,我完全支持这样简单的重构。
(更新)我刚刚在制作中尝试了这个,在我申请迁移时遇到了一个奇怪的警告。 它说:
The following content types are stale and need to be deleted: yourapp | foo Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'.
我回答“不”,一切似乎都很好。
在models.py
进行更改,然后运行
./manage.py schemamigration --auto myapp
当您检查迁移文件时,您会看到它删除了一个表并创build了一个新表
class Migration(SchemaMigration): def forwards(self, orm): # Deleting model 'Foo' db.delete_table('myapp_foo') # Adding model 'Bar' db.create_table('myapp_bar', ( ... )) db.send_create_signal('myapp', ['Bar']) def backwards(self, orm): ...
这不是你想要的。 而是编辑迁移,使其看起来像:
class Migration(SchemaMigration): def forwards(self, orm): # Renaming model from 'Foo' to 'Bar' db.rename_table('myapp_foo', 'myapp_bar') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter( app_label='myapp', model='foo').update(model='bar') def backwards(self, orm): # Renaming model from 'Bar' to 'Foo' db.rename_table('myapp_bar', 'myapp_foo') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')
在没有update
语句的情况下, db.send_create_signal
调用将使用新的模型名称创build一个新的ContentType
。 但是,如果有数据库对象指向它(例如,通过GenericForeignKey
), update
ContentType
就更好了。
另外,如果你已经重命名了重命名模型的外键列,请不要忘记
db.rename_column(myapp_model, foo_id, bar_id)
南不能自己做 – 它怎么知道Bar
代表什么Foo
过去? 这是我写一个自定义迁移的东西。 您可以像上面所做的那样在代码中更改ForeignKey
,然后只是重命名适当的字段和表格,您可以按照自己的意愿进行操作。
最后,你真的需要这样做吗? 我还没有需要重新命名模型 – 模型名称只是一个实现细节 – 特别是在verbose_name
Meta选项可用的情况下。
我遵循上面的Leopd的解决scheme。 但是,这并没有改变模型的名称。 我在代码中手动更改了它(在相关的模型中也被称为FK)。 并做了另一个南方移民,但有一个 – 假的select。 这使模型名称和表名称是相同的。
刚刚意识到,可以先从更改模型名称开始,然后在应用它们之前编辑迁移文件。 更干净。