问题:使用Django / South重命名模型的最简单方法?
我一直在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)
为简单起见,我只是尝试将名称从更改Foo
为Bar
,但现在忽略其中的foo
成员FooTwo
。
使用South进行此操作最简单的方法是什么?
- 我可能可以进行数据迁移,但这似乎很复杂。
- 编写一个自定义迁移,例如
db.rename_table('city_citystate', 'geo_citystate')
,但是在这种情况下我不确定如何修复外键。 - 您知道一种更简单的方法吗?
回答 0
为了回答您的第一个问题,简单的模型/表重命名非常简单。运行命令:
./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'.
我回答“不”,一切似乎都很好。
回答 1
进行更改models.py
,然后运行
./manage.py schemamigration --auto myapp
检查迁移文件时,您会看到它删除了一个表并创建了一个新表。
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
调用将ContentType
使用新的模型名称创建一个新的模型。但它最好只update
在ContentType
你已经拥有的情况下有数据库对象指向它(例如,通过一GenericForeignKey
)。
另外,如果您已经重命名了某些列,这些列是重命名模型的外键,请不要忘记
db.rename_column(myapp_model, foo_id, bar_id)
回答 2
南方本身不能做-怎么知道这Bar
代表Foo
过去?我将为此编写自定义迁移。您可以ForeignKey
像上面所做的那样更改in代码,然后只是重命名适当的字段和表的一种情况,您可以根据需要进行任何操作。
最后,您真的需要这样做吗?我还不需要重命名模型-模型名称只是实现细节-特别是考虑到verbose_name
Meta选项的可用性。
回答 3
我遵循了上面Leopd的解决方案。但是,这并没有更改型号名称。我在代码中手动更改了它(在相关模型中也将其称为FK)。并进行了另一个南迁,但带有–fake选项。这使得模型名称和表名称相同。
刚意识到,可以先从更改模型名称开始,然后在应用迁移文件之前编辑迁移文件。干净得多。