我有一个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
?
更改列名称时保留该列中数据的最佳方法是什么?
答案 0 :(得分:27)
为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 对其进行了测试,它可以自动检测字段是否被重命名,并提供重命名选项,而不是删除并创建新字段
初始
发布(如果仍然对某人有用)。
对于 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)
可以在不进行任何手动迁移文件编辑的情况下重命名字段:
python3 manage.py makemigrations
python3 manage.py makemigrations
系统会提示您:
您是否将模型。 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
进行迁移。在我的情况下,终端历史记录如下:
注意:我一次没有测试多个字段。
答案 8 :(得分:0)
正如其他回复中所指出的,现在使用 db_column
可以很容易地重命名字段而不更改数据库。但是生成的迁移实际上会创建一些 SQL 语句。您可以通过在迁移时调用 ./manage.py sqlmigrate ...
来验证这一点。
为了避免对您的数据库产生任何影响,您需要使用 SeparateDatabaseAndState
向 Django 表明它不需要在 DB 中执行任何操作。
如果您想了解更多信息,我写了一篇关于此的小article。
答案 9 :(得分:-1)
1.编辑django模型上的字段名称
2.创建一个空迁移,如下所示:
$ python manage.py makemigrations --empty testApp(testApp 是您的应用程序名称)
编辑最近创建的空迁移文件
操作 = [ migrations.RenameField('你的模型', '旧字段', '新字段'), ]
应用迁移
$ python manage.py migrate
数据库列名称将更改为新名称。