我一直在寻找South的网站,谷歌和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
成员。
使用南方最简单的方法是什么?
db.rename_table('city_citystate', 'geo_citystate')
,但我不确定在这种情况下如何修复外键。答案 0 :(得分:129)
要回答您的第一个问题,简单的模型/表重命名非常简单。运行命令:
./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 :(得分:66)
在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 :(得分:5)
南方不能自己做 - 它如何知道Bar
代表Foo
过去常见的东西?这是我为自己编写自定义迁移的事情。您可以像上面那样更改代码中的ForeignKey
,然后只需重命名相应的字段和表格即可,您可以按照自己的方式进行操作。
最后,你真的需要这样做吗?我还需要重命名模型 - 模型名称只是一个实现细节 - 特别是考虑到verbose_name
Meta选项的可用性。
答案 3 :(得分:-1)
我按照上面的Leopd解决方案。但是,这并没有改变模型名称。我在代码中手动更改了它(也在相关模型中,它被称为FK)。并完成了另一次南迁,但有--fake选项。这使得模型名称和表名称相同。
刚刚意识到,可以先从更改模型名称开始,然后在应用之前编辑迁移文件。更干净。