django 1.8 官方文档翻译: 2-4-4 编写数据库迁移

编写数据库迁移

这一节介绍你可能遇到的在不一样状况下如何分析和编写数据库迁移. 有关迁移的入门资料,请查看 the topic guide.html

数据迁移和多数据库

在使用多个数据库时,须要解决是否针对某个特定数据库运行迁移。例如,你可能 只 想在某个特定数据库上运行迁移。python

为此你能够在RunPython中经过查看schema_editor.connection.alias 属性来检查数据库链接别名:git

from django.db import migrations

def forwards(apps, schema_editor):
    if not schema_editor.connection.alias == 'default':
        return
    # Your migration code goes here

class Migration(migrations.Migration):

    dependencies = [
        # Dependencies to other migrations
    ]

    operations = [
        migrations.RunPython(forwards),
    ]
Django 1.8 中新增。

你也能够提供一个提示做为 **hints参数传递到数据库路由的allow_migrate() 方法:github

myapp/dbrouters.py
class MyRouter(object):

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if 'target_db' in hints:
            return db == hints['target_db']
        return True

而后,要在你的迁移中利用,执行如下操做:数据库

from django.db import migrations

def forwards(apps, schema_editor):
    # Your migration code goes here

class Migration(migrations.Migration):

    dependencies = [
        # Dependencies to other migrations
    ]

    operations = [
        migrations.RunPython(forwards, hints={'target_db': 'default'}),
    ]

若是你的RunPython或者RunSQL操做只对一个模型有影响,最佳实践是将model_name做为提示传递,使其尽量对路由可见。这对可复用的和第三方应用极其重要。django

添加惟一字段的迁移

若是你应用了一个“朴素”的迁移,向表中一个已存在的行中添加了一个惟一的非空字段,会产生错误,由于位于已存在行中的值只会生成一次。因此须要移除惟一性的约束。app

因此,应该执行下面的步骤。在这个例子中,咱们会以默认值添加一个非空的UUIDField字段。你能够根据你的须要修改各个字段。ide

  • 把default=...和unique=True参数添加到你模型的字段中。在这个例子中,咱们默认使用uuid.uuid4。oop

  • 运行 makemigrations 命令。ui

  • 编辑建立的迁移文件。

生成的迁移类看上去像这样:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0003_auto_20150129_1705'),
    ]

    operations = [
        migrations.AddField(
            model_name='mymodel',
            name='uuid',
            field=models.UUIDField(max_length=32, unique=True, default=uuid.uuid4),
        ),
    ]

你须要作三处更改:

  • 从已生成的迁移类中复制,添加第二个AddField操做,并改成AlterField。

  • 在第一个AddField操做中,把unique=True改成 null=True,这会建立一个中间的null字段。

  • 在两个操做之间,添加一个RunPython或RunSQL操做为每一个已存在的行生成一个惟一值(例如UUID)。

最终的迁移类应该看起来是这样:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import uuid

def gen_uuid(apps, schema_editor):
    MyModel = apps.get_model('myapp', 'MyModel')
    for row in MyModel.objects.all():
        row.uuid = uuid.uuid4()
        row.save()

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0003_auto_20150129_1705'),
    ]

    operations = [
        migrations.AddField(
            model_name='mymodel',
            name='uuid',
            field=models.UUIDField(default=uuid.uuid4, null=True),
        ),
        # omit reverse_code=... if you don't want the migration to be reversible.
        migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
        migrations.AlterField(
            model_name='mymodel',
            name='uuid',
            field=models.UUIDField(default=uuid.uuid4, unique=True),
        ),
    ]

如今你能够像日常同样使用migrate命令应用迁移。

注意若是你在这个迁移运行时让对象被建立,就会产生竞争条件(race condition)。在AddField以后, RunPython以前建立的对象会覆写他们原始的uuid。

译者:飞龙,原文:Writing migrations

本文以 CC BY-NC-SA 3.0 协议发布,转载请保留做者署名和文章出处。

Django 文档协做翻译小组人手紧缺,有兴趣的朋友能够加入咱们,彻底公益性质。交流群:467338606。

若是以为文章还不错,能够扫描下面的二维码来打赏我。

相关文章
相关标签/搜索