迁移django-model字段名称更改而不会丢失数据

时间:2010-08-16 23:09:20

标签: django-models django-south custom-fields customcolumn

我有一个django项目,其中包含一个已包含数据的数据库表。我想更改字段名称而不会丢失该列中的任何数据。我原来的计划是简单地以一种实际上不会改变db表名称的方式更改模型字段名称(使用db_column列参数):

原始模型:

class Foo(models.Model):
  orig_name = models.CharField(max_length=50)

新模型:

class Foo(models.Model):
  name = models.CharField(max_length=50, db_column='orig_name')

但是,运行South的schemamigration --auto会生成一个迁移脚本,删除原始列orig_name,并添加一个新列name,这会产生不必要的副作用,即删除该列中的数据。 (我也很困惑为什么South想要更改db中列的名称,因为我对db_column的理解是它允许更改模型字段名而不更改数据库表列的名称)。

如果我无法在不更改db字段的情况下更改模型字段,我想我可以更直接地更改名称:

原始模型:

class Foo(models.Model):
  orig_name = models.CharField(max_length=50)

新模型:

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

无论我最终使用哪种策略(我更喜欢第一种,但会找到第二种可接受的策略),我主要担心的是确保我不会丢失该列中已有的数据。

这是否需要多步骤流程? (例如1.添加列,2。将数据从旧列迁移到新列,以及3.删除原始列) 或者我可以使用db.alter_column

之类的内容更改迁移脚本

更改列名称时保留该列中数据的最佳方法是什么?

10 个答案:

答案 0 :(得分:27)

在保留DB字段

的同时更改字段名称

为Django 1.8+添加答案(使用Django本地迁移,而不是南方)。

首先添加db_column属性进行迁移,然后重命名该字段。 Django理解第一个是无操作(因为它改变了db_column以保持不变),并且第二个是无操作(因为它不进行模式更改)。我实际上检查了日志,看看没有架构更改......

operations = [
    migrations.AlterField(
        model_name='mymodel',
        name='oldname',
        field=models.BooleanField(default=False, db_column=b'oldname'),
    ),
    migrations.RenameField(
        model_name='mymodel',
        old_name='oldname',
        new_name='newname',
    ),
]

答案 1 :(得分:17)

很容易修复。但您必须自己修改迁移。

使用db.rename_column,而不是删除和添加列。您只需修改schemamigration --auto

创建的迁移即可

答案 2 :(得分:5)

实际上使用Django 1.10,只需重命名模型中的字段然后运行makemigrations,立即识别操作(即一个字段消失,另一个字段代替它):

$ ./manage.py makemigrations
Did you rename articlerequest.update_at to articlerequest.updated_at (a DateTimeField)? [y/N] y
Migrations for 'article_requests':
  article_requests/migrations/0003_auto_20160906_1623.py:
    - Rename field update_at on articlerequest to updated_at

答案 3 :(得分:4)

我遇到过这种情况。我想更改模型中的字段名称,但保持列名相同。

我做的方法是schemamigration --empty [app] [some good name for the migration]。问题是,就South而言,更改模型中的字段名称是需要处理的更改。因此必须创建迁移。但是,我们知道在数据库方面没有什么必须做的。 因此,空迁移可以避免对数据库进行不必要的操作,同时满足南方需要处理它认为是变更的内容。

请注意,如果您使用loaddata或使用Django的测试夹具工具(在幕后使用loaddata)。您必须更新灯具以使用新的字段名称,因为灯具基于模型字段名称,而不是数据库字段名称。

对于数据库中列名称发生更改的情况,我绝不建议使用db.rename_column进行列迁移。我使用sjh在this answer中描述的方法:

  

我已将新列添加为一个schemamigration,然后创建了一个数据迁移以将值移动到新字段中,然后创建第二个schemamigration以删除旧列

正如我在问题的comment中所指出的那样,db.rename_column的问题在于它不会将约束与列一起重命名。问题是否仅仅是装饰性的,或者这是否意味着未来的迁移可能会失败,因为它无法找到约束,我不知道。

答案 4 :(得分:3)

更新

使用 Django 2.0.9 对其进行了测试,它可以自动检测字段是否被重命名,并提供重命名选项,而不是删除并创建新字段 enter image description here

初始

发布(如果仍然对某人有用)。

对于 Django 2.0 ,只需重命名模型中的字段

class Foo(models.Model):
    orig_name = models.CharField(max_length=50)

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

现在运行python manage.py makemigrations 它将通过删除旧字段并添加新字段的操作来生成迁移。

继续,将其更改为跟随。

operations = [
    migrations.RenameField(
        model_name='foo',
        old_name='orig_name',
        new_name='name')
]

现在运行python manage.py migrate,它将在数据库中重命名该列而不会丢失数据。

答案 5 :(得分:1)

我在Django 1.7.7上遇到了这种情况。我最终做了以下对我有用的工作。

./manage.py makemigrations <app_name> --empty

添加了一个不会触及数据库的migrations.RenameField的简单子类:

class RenameFieldKeepDatabaseColumn(migrations.RenameField):
def database_backwards(self, app_label, schema_editor, from_state, to_state):
    pass

def database_forwards(self, app_label, schema_editor, from_state, to_state):
    pass

答案 6 :(得分:1)

可以在不进行任何手动迁移文件编辑的情况下重命名字段:

  1. 将db_column = OLD_FIELD_NAME 添加到原始字段。
  2. 运行:python3 manage.py makemigrations
  3. OLD_FIELD_NAME 中的字段重命名为 NEW_FIELD_NAME
  4. 运行:python3 manage.py makemigrations
  5. 系统会提示您:

      

    您是否将模型 OLD_FIELD_NAME 重命名为模型 NEW_FIELD_NAME (一个ForeignKey)? [y / N] y

    这将生成两个迁移文件而不是一个,尽管两个迁移都是自动生成的。

    此过程适用于Django 1.7 +。

答案 7 :(得分:1)

更新 Django 3.1 中,一次仅更改一个字段非常简单。

就我而言:

旧字段名称为:is_admin 新的字段名称为:is_superuser

当我通过python manage.py makemigrations进行迁移时,它询问我是否要重命名该字段。我只是点击y重命名。然后,我通过python manage.py migrate进行迁移。在我的情况下,终端历史记录如下: enter image description here

注意:我一次没有测试多个字段。

答案 8 :(得分:0)

正如其他回复中所指出的,现在使用 db_column 可以很容易地重命名字段而不更改数据库。但是生成的迁移实际上会创建一些 SQL 语句。您可以通过在迁移时调用 ./manage.py sqlmigrate ... 来验证这一点。

为了避免对您的数据库产生任何影响,您需要使用 SeparateDatabaseAndState 向 Django 表明它不需要在 DB 中执行任何操作。

如果您想了解更多信息,我写了一篇关于此的小article

答案 9 :(得分:-1)

1.编辑django模型上的字段名称

2.创建一个空迁移,如下所示:

$ python manage.py makemigrations --empty testApp(testApp 是您的应用程序名称)

  1. 编辑最近创建的空迁移文件

    操作 = [ migrations.RenameField('你的模型', '旧字段', '新字段'), ]

  2. 应用迁移
    $ python manage.py migrate

数据库列名称将更改为新名称。

相关问题