使用Django/South重命名模型的最简单方法?

vau*_*och 141 python django rename django-models django-south

我一直在寻找南方网站,谷歌和SO的答案,但找不到一个简单的方法来做到这一点.

我想用South重命名一个Django模型.说你有以下内容:

class Foo(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)
Run Code Online (Sandbox Code Playgroud)

并且你想将Foo转换为Bar,即

class Bar(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Bar)
Run Code Online (Sandbox Code Playgroud)

为了简单起见,我只是尝试将名称从更改FooBar,但暂时忽略该foo成员FooTwo.

使用南方最简单的方法是什么?

  1. 我可能会进行数据迁移,但这似乎很复杂.
  2. 编写自定义迁移,例如db.rename_table('city_citystate', 'geo_citystate'),但在这种情况下我不确定如何修复外键.
  3. 你知道一种更简单的方法吗?

Leo*_*opd 130

要回答您的第一个问题,简单的模型/表重命名非常简单.运行命令:

./manage.py schemamigration yourapp rename_foo_to_bar --empty
Run Code Online (Sandbox Code Playgroud)

(更新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')   
Run Code Online (Sandbox Code Playgroud)

您可以使用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'.
Run Code Online (Sandbox Code Playgroud)

我回答"不",一切似乎都很好.

  • 请注意,这不会重命名该表上的索引.如果将来创建一个与旧表名称相同的新表,则可能会从索引名称冲突中获取错误.我们使用的是这种技术,但从现在开始,我们将明确创建新表,迁移数据,然后删除旧表. (5认同)
  • 我在2011年9月2日使用了这种技术而没有出现任何错误.也许较新版本的南方解决了错误的问题. (4认同)
  • 我能够通过使用--auto而不是--empty创建模式迁移来避免Leopd的错误消息.然后,我编辑了迁移文件,将表的删除/创建更改为db.rename_table()调用.这看起来效果很好. (3认同)
  • 自动生成的表中的列名(例如原始模型的M2M表)也不会通过此方法迁移. (3认同)

Jia*_*ian 66

进行更改models.py然后运行

./manage.py schemamigration --auto myapp
Run Code Online (Sandbox Code Playgroud)

检查迁移文件时,您将看到它删除了一个表并创建了一个新表

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):
        ...
Run Code Online (Sandbox Code Playgroud)

这不是你想要的.而是编辑迁移,使其看起来像:

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')
Run Code Online (Sandbox Code Playgroud)

如果没有该update语句,db.send_create_signal调用将ContentType使用新的模型名称创建一个新的.但它最好只updateContentType你已经拥有的情况下有指向它的数据库对象(例如,通过一GenericForeignKey).

此外,如果您重命名了一些作为重命名模型的外键的列,请不要忘记

db.rename_column(myapp_model, foo_id, bar_id)
Run Code Online (Sandbox Code Playgroud)

  • +1用于在contenttypes表中重命名模型 (8认同)
  • 我收到错误,KeyError:"此迁移中没有来自应用'contenttypes'的模型'contenttype'." 另外,我有一个django_content_type表,但没有contenttypes表.(Django 1.6) (2认同)
  • @Seth我通过在单独的数据迁移中更新ContentType模型并通过使用``--frozen``标志将``contenttypes.ContentType``模型添加到冻结模型来解决这个问题. /manage.py datamigration``.例如:``./manage.py datamigration --frozen contenttypes myapp update_contenttypes``.然后使用上面指定的内容类型更新代码编辑myapp_migrations/NNNN_update_contenttypes.py. (2认同)

Dom*_*ger 5

南方不能自己做 - 它如何知道Bar代表过去的东西Foo?这是我为自己编写自定义迁移的事情.您可以ForeignKey像上面那样更改您的代码,然后只需重命名相应的字段和表格,您可以按照自己的方式进行操作.

最后,你真的需要这样做吗?我还需要重命名模型 - 模型名称只是一个实现细节 - 特别是考虑到verbose_nameMeta选项的可用性.

  • 或者,在代码中重命名模型,但使用`db_table`Meta选项保持数据库表名相同. (7认同)