<!--
譯者:Github@wizardforcel
-->
# 編寫數據庫遷移 #
這一節介紹你可能遇到的在不同情況下如何分析和編寫數據庫遷移. 有關遷移的入門資料,請查看 the topic guide.
## 數據遷移和多數據庫 ##
在使用多個數據庫時,需要解決是否針對某個特定數據庫運行遷移。例如,你可能 只 想在某個特定數據庫上運行遷移。
為此你可以在RunPython中通過查看schema_editor.connection.alias 屬性來檢查數據庫連接別名:
```
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() 方法:
```
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作為提示傳遞,使其盡可能對路由可見。這對可復用的和第三方應用極其重要。
## 添加唯一字段的遷移 ##
如果你應用了一個“樸素”的遷移,向表中一個已存在的行中添加了一個唯一的非空字段,會產生錯誤,因為位于已存在行中的值只會生成一次。所以需要移除唯一性的約束。
所以,應該執行下面的步驟。在這個例子中,我們會以默認值添加一個非空的UUIDField字段。你可以根據你的需要修改各個字段。
+ 把default=...和unique=True參數添加到你模型的字段中。在這個例子中,我們默認使用uuid.uuid4。
+ 運行 makemigrations 命令。
+ 編輯創建的遷移文件。
生成的遷移類看上去像這樣:
```
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。
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架