Django 迁移旧数据到新模型

Django 的迁移系统在大多数情况下都无需人工干涉,但是遇到需要迁移数据的场景就必须要人手工介入了。还好,在 Django 迁移系统的帮助下这并不复杂。

模型

假设你的 ymc 应用中有以下的 BookNewBook 模型:

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)

我们的目标是将 Booktitle 字段的值复制到 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 中,只有依赖的所有迁移执行完毕后,此迁移文件才会开始执行。

posted @ 2021-01-23 13:52  Veoco  阅读(88)  评论(0编辑  收藏  举报