Django 迁移旧数据到新模型
Django 的迁移系统在大多数情况下都无需人工干涉,但是遇到需要迁移数据的场景就必须要人手工介入了。还好,在 Django 迁移系统的帮助下这并不复杂。
模型
假设你的 ymc
应用中有以下的 Book
和 NewBook
模型:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255)
class NewBook(models.Model):
name = models.CharField(max_length=255)
我们的目标是将 Book
中 title
字段的值复制到 name
字段。
编写迁移文件
首先要创建一个空迁移文件:
python manage.py makemigrations --empty ymc
在你应用的 migrations
目录中会有一个最新的空白迁移,其中 dependencies
中的依赖是上一个迁移文件,如此:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('ymc', '0001_initial'),
]
operations = []
然后编写迁移函数,无论什么名字都可以,只要 Python 允许,我是这样写的:
def move_book(apps, schema_editor):
Book = apps.get_model('ymc', 'Book')
NewBook = apps.get_model('ymc', 'NewBook')
for book in Book.objects.all():
new_book = NewBook(name=book.title)
new_book.save()
迁移函数要确保参数签名一致,而模型必须从 app.get_model()
获取,参数为 (应用名,模型名),之后就是遍历 Book
的值复制到新的 NewBook
中。最后把函数加入到 operations
列表中,运行就大功告成了,完整迁移文件:
from django.db import migrations
def move_book(apps, schema_editor):
Book = apps.get_model('ymc', 'Book')
NewBook = apps.get_model('ymc', 'NewBook')
for book in Book.objects.all():
new_book = NewBook(name=book.title)
new_book.save()
class Migration(migrations.Migration):
dependencies = [
('ymc', '0001_initial'),
]
operations = [move_book, migrations.RunPython.noop]
更多细节
你是否注意到 operations
列表中多了一个 migrations.RunPython.noop
?操作列表中的第二项是反向迁移时应用的函数,与之对应的第一项是正向迁移时应用的函数。你可以留空只保留第一个函数,但是这样在回滚迁移时会报错,而 migrations.RunPython.noop
意味着什么也不做,可以在回滚操作无需特殊处理时防止报错。
在这里我们的依赖只有 ('ymc', '0001_initial')
,但有些时候需要添加额外的依赖。比如此次迁移需要另一个应用的某个迁移文件完成后才能开始,那就把指定的 (应用名, 文件名)
加入 dependencies
中,只有依赖的所有迁移执行完毕后,此迁移文件才会开始执行。