Django - 如何使用 South 重命名模型字段?

Posted

技术标签:

【中文标题】Django - 如何使用 South 重命名模型字段?【英文标题】:Django - How to rename a model field using South? 【发布时间】:2011-03-15 05:46:22 【问题描述】:

我想更改模型中特定字段的名称:

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

应该改为:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

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

【问题讨论】:

另见 ***.com/questions/2862979/… 以重命名 model 而不是 model 字段 【参考方案1】:

您可以使用db.rename_column 函数。

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

db.rename_column 的第一个参数是表名,所以记住Django creates table names 的方式很重要:

Django 自动从模型类的名称和包含它的应用程序中派生数据库表的名称。模型的数据库表名是通过将模型的“应用标签”(您在 manage.py startapp 中使用的名称)与模型的类名连接起来构建的,它们之间使用下划线。

如果您有一个多字的驼峰式模型名称,例如 ProjectItem,则表名称将为app_projectitem(即,即使在projectitem 之间也不会插入下划线虽然它们是驼色的)。

【讨论】:

这适用于 name\full_name,但不适用于关系字段,对吧? 重要提示:如果您要使用它,请确保“app_foo”是数据库表名,例如:“mainapp_profile”,“name”是数据库的旧列名(不是模型字段名称),例如:“user_id”和“full_name”将是您希望列具有的新名称(同样,数据库列而不是字段名称)。所以: db.rename_column('mainapp_profile', 'user_id', 'new_user_id') 另外,如果您正在处理外键,重命名时应该在其中包含“_id”部分。 如果您手动执行此 db.rename_column 您可能需要在之后进行虚假架构迁移以清理备份。那是首先通过重命名列来迁移更改。然后修复模型(以获得更新的名称),然后执行 ./manage.py schemamigration app --auto && ./manage.py migrate app --fake)。 你也可以使用 ./manage.py schemamigration my_app renaming_column_x --empty 来创建一个空的migration并将代码放入其中 --empty 没有多大帮助,而是使用 --auto 并修改创建的迁移。这样它就不会声明字段已被删除,以便下次迁移 models.py。【参考方案2】:

这是我的工作:

    更改模型中的列名(在本例中为myapp/models.py) 运行./manage.py schemamigration myapp renaming_column_x --auto

注意renaming_column_x 可以是您喜欢的任何名称,它只是为迁移文件提供描述性名称的一种方式。

这将为您生成一个名为 myapp/migrations/000x_renaming_column_x.py 的文件,该文件将删除您的旧列并添加一个新列。

修改此文件中的代码以将迁移行为更改为简单的重命名:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')

【讨论】:

命令中列的名称是什么? xcolumn_x? 您所指的命令部分只是用来命名迁移,它可以是任何你喜欢的。编辑时需要在迁移文件中指定列名。 首先创建--auto 迁移是一个很好的提示。它避免了 South ORM Freezer 的问题,如果迁移只有 forwardsbackwards 方法,但不包含冻结的 model 对象,则会出现问题。 如何回答 south 的问题“由于您要删除此字段,因此必须指定默认值”? 我对这种方法的一个问题是db.rename_column 没有重命名与列关联的约束。迁移仍然有效,但您将拥有以旧列名命名的约束。我有一个具有唯一性约束的列,使用此方法重命名它,测试唯一性约束是否仍然存在并出现错误,但约束本身的名称仍在使用旧的列名。也许一个明确的db.delete_uniquedb.create_unique 会做到这一点,但我决定采用 sjh 的解决方案。【参考方案3】:

我不知道 db.rename 列,听起来很方便,但是在过去我将新列添加为一个 schemamigration,然后创建了一个 datamigration 以将值移动到新字段中,然后创建第二个 schemamigration 以删除旧专栏

【讨论】:

我也是。 schema-data-schema 技术的问题在于您最终会为您的字段/模型使用不同的名称。如果您使用规范名称来启用调度程序,有时这会成为问题...... 我刚刚尝试过,但由于名称冲突,它不起作用。我有完全相同的 FK,但名称不同。它没有验证。所以,不要这样做。 @jonathan,他想要不同的名字!...@pilgrim,愿意发布一些代码吗?这周我已经做了好几次了,如果你的模型没有验证,那么南就不会创建迁移。 这可行,但可能会比其他人建议的“rename_column”慢。我知道 mysql 可以很快地执行“ALTER TABLE ...重命名列”(或其他任何内容)。 @Rory db.rename_column 不会为您重命名约束,因此您必须手动处理。如果您忘记执行此操作,则迁移将起作用,但您不知道可能存在仍在使用旧列名的约束。我不清楚这个问题是否仅仅是表面上的问题,或者是否在未来的迁移中应该操纵或放弃约束,South 将无法找到它。无论如何,像 sjh 建议的那样在这里做是安全的方法:你可以让 South 弄清楚它应该弄清楚什么。【参考方案4】:

Django 1.7 引入了Migrations,所以现在您甚至不需要安装额外的包来管理您的迁移。

要重命名模型,您需要先创建空迁移:

$ manage.py makemigrations <app_name> --empty

然后你需要像这样编辑你的迁移代码:

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

然后你需要运行:

$ manage.py migrate <app_name>

【讨论】:

【参考方案5】:

只需更改模型并在 1.9 中运行 makemigrations

Django 自动检测到你已经删除并创建了一个字段,并询问:

Did you rename model.old to model.new (a IntegerField)? [y/N]

说是,就会创建正确的迁移。魔法。

【讨论】:

【参考方案6】:
    在项目设置文件中将south 添加到已安装的应用程序中。 注释掉添加/修改的字段/表格。 $ manage.py Schemamigration &lt;app_name&gt; --initial $ manage.py migrate &lt;app_name&gt; --Fake 取消注释字段并写入修改后的字段 $ manage.py Schemamigration --auto $ manage.py migrate &lt;app_name&gt;

如果您使用 'pycharm',则可以使用 'ctrl+shift+r' 代替 'manage.py' ,并使用 'shift ' 作为参数。

【讨论】:

以上是关于Django - 如何使用 South 重命名模型字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Django 重命名模型?

在 MySQL 中重命名外键列

在 MySQL 中重命名外键列

如何从默认 Django 模型重命名模型字段?

如何在 Django 中使用 South 将数据从一个模型迁移到另一个模型?

当有外部引用时,如何重命名 Django 模型的文件夹?