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。

若是以爲文章還不錯,能夠掃描下面的二維碼來打賞我。

相關文章
相關標籤/搜索