這一節介紹你可能遇到的在不一樣狀況下如何分析和編寫數據庫遷移. 有關遷移的入門資料,請查看 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。
若是以爲文章還不錯,能夠掃描下面的二維碼來打賞我。