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


209

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

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进行此操作最简单的方法是什么?


7
另请参阅stackoverflow.com/questions/2862979/…,以重命名模型而不是重命名模型字段
机械蜗牛

Answers:


230

您可以使用该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如何创建表名很重要:

Django会自动从您的模型类的名称和包含该表的应用程序中获取数据库表的名称。通过将模型的“应用程序标签”(即您在manage.py startapp中使用的名称)连接到模型的类名称,并在其之间加下划线,来构造模型的数据库表名称。

在你有一个多措辞,骆驼套管型号名称的情况下,如项目项,表名会app_projectitem(即下划线不会之间插入projectitem即使它们是骆驼式大小写)。


2
那将对name \ full_name起作用,但对关系字段不起作用,对吗?
乔纳森

23
重要说明:如果要使用此名称,请确保“ app_foo”是数据库表名称,例如:“ mainapp_profile”,“ name”是数据库的旧列名称(而不是模型字段名称),例如:“ user_id”和“ full_name”将是您希望该列具有的新名称(再次是数据库列,而不是字段名)。因此:db.rename_column('mainapp_profile','user_id','new_user_id')此外,如果要处理外键,重命名时应在其中包含“ _id”部分。
Gezim

3
如果您手动执行此db.rename_column,则之后可能必须执行伪造的schemamigration来清除备份内容。首先,通过重命名列来迁移更改。然后修复模型(具有更新的名称),然后执行./manage.py schemamigration应用--auto && ./manage.py迁移应用--fake)。
jimbob博士2011年

24
您还可以使用./manage.py schemamigration程序my_app renaming_column_x --empty创建一个空的迁移,只是在它的代码放置
莉莲·利维

11
--empty没有太大帮助,而是使用--auto并修改创建的迁移。这样,它将不会声明字段已被删除,以便下次迁移models.py。
2013年

39

这是我的工作:

  1. 在模型中更改列名(在本示例中为myapp/models.py
  2. ./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')

您的命令中列的名称是什么?x还是column_x
andilabs 2014年

您所指的命令部分仅用于命名迁移,它可以是您喜欢的任何东西。编辑时,需要在迁移文件中指定列名。
donturner 2014年

2
首先创建--auto迁移是一个很好的技巧。它避免了South ORM Freezer出现的问题,如果迁移仅包含forwardsbackwards方法,但不包含冻结的model对象,则会出现该问题。
mwcz

如何回答South的问题“由于要删除此字段,因此必须指定默认值”?
布莱斯2014年

3
我使用此方法的一个问题是db.rename_column不会重命名与列关联的约束。迁移仍然可以进行,但是您将拥有以旧列名称命名的约束。我有一列具有唯一性约束的列,使用此方法将其重命名,测试了唯一性约束仍然存在并收到错误,但是约束本身的名称仍使用旧列名。也许是明确的,db.delete_unique并且db.create_unique会做到的,但是我决定采用sjh的解决方案。
2014年

15

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


我也是。模式数据模式技术的问题在于,您最终为字段/模型使用了不同的名称。如果您使用规范名称来启用调度程序,则有时会出现问题...
Jonathan

我只是尝试了一下,但由于名称冲突而无法使用。我的FK完全相同,但名称不同。没有验证。所以,要这样做。
Gezim

2
@jonathan,他想要不同的名字!... @pilgrim,愿意张贴一些代码吗?我本周已经做了几次,如果您的模型没有通过验证,那么South不会创建迁移。
sjh

可以,但是可能比其他人建议的“ rename_column”慢。我知道MySQL可以很快地执行“ ALTER TABLE ...重命名列”(或其他操作)。
罗里

1
@Rory db.rename_column不会为您重命名约束,因此您必须手动处理它。如果您忘记这样做,则迁移将正常进行,除非您不知道,可能仍然存在使用旧列名的约束。对于我来说,目前还不清楚这个问题是仅仅是表面上的问题,还是将来的迁移中应该操纵约束或放开约束的问题,南方将无法找到它。无论如何,在这里像sjh所建议的那样做是安全的方法:您可以让South弄清楚它应该弄清楚什么。
2014年

10

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

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

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

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

同意,就可以创建正确的迁移。魔法。


0
  1. south在项目设置文件中添加到已安装的应用程序。
  2. 注释掉添加/修改的字段/表。
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. 取消注释该字段并写入修改后的字段
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.