從入門到深入及數據遷移(Django遷移)

Django遷移:入門

從1.7版開始,Django就內置了對數據庫遷移的支持。 在Django中,數據庫遷移通常與模型密切相關:每當編寫新模型時,還會生成遷移以在數據庫中創建必要的表。 但是,遷移可以做得更多。

在本文中,熟悉Django遷移並學習以下內容:

  • 如何在不編寫任何SQL的情況下創建數據庫表
  • 更改模型後如何自動修改數據庫
  • 如何還原對數據庫所做的更改

遷移解決的問題

如果不熟悉Django或Web開發,可能不熟悉數據庫遷移的概念,它們帶來的好處可能並不明顯。

首先,讓我們快速定義幾個術語。 Django旨在與關係數據庫一起使用,存儲在PostgreSQL,MySQL或SQLite等關係數據庫管理系統中。

在關係數據庫中,數據以表格形式組織。數據庫表具有一定數量的列,但它可以包含任意數量的行。每列都有一個特定的數據類型,如某個特定最大長度的字符串或正整數。所有表、它的列,以及其各自數據類型的描述稱爲數據庫模式。

Django支持的所有數據庫系統都使用SQL語言來創建,讀取,更新和刪除關係數據庫中的數據。 SQL還用於創建,更改和刪除數據庫表本身。

直接使用SQL可能非常麻煩,因此爲了讓編程更輕鬆,Django附帶了一個對象關係映射器,簡稱ORM。 ORM將關係數據庫映射到面向對象編程的世界。可以在Python中編寫Django模型,而不是在SQL中定義數據庫表。使用模型定義數據庫字段,這些字段對應於其在數據庫表中的列。

以下是Django模型類如何映射到數據庫表的示例:
在這裏插入圖片描述

但是隻是在Python文件中定義一個模型類後,並不會使數據庫表憑空出現。 使用數據庫遷移可以創建數據庫表來存儲Django模型。 此外,無論何時對模型進行更改(如添加字段),也必須更改數據庫。 遷移正是處理這個問題。

以下是Django遷移讓編程更輕鬆的幾種方式。

不使用SQL進行數據庫更改

如果沒有遷移,每次要更改模型定義時修改數據庫模式時,則必須連接到數據庫並鍵入一堆SQL命令,或者使用PHPMyAdmin等圖形工具。

在Django中,遷移主要是用Python編寫的,因此除非有非常高級的用法,否則不必知道任何SQL。

避免重複

創建模型後,然後編寫SQL語句來其創建數據庫表將是重複的。

從模型生成遷移,將不會做重複的工作。

確保模型定義和數據庫模式同步

通常,有多個數據庫實例,例如,團隊中每個開發人員都有一個數據庫,用於測試的數據庫和包含實時數據的數據庫。

如果沒有遷移,則必須對每個數據庫執行任何模式更改,並且必須跟蹤已對哪個數據庫進行了哪些更改。

使用Django遷移,可以輕鬆地使多個數據庫與模型保持同步。

跟蹤版本控制中的數據庫模式更改

像Git這樣的版本控制系統非常適合代碼,但對數據庫模式來說並不是那麼適用。

由於遷移在Django中是純Python,所以可以將它們像其他代碼一樣放在版本控制系統中。

到目前爲止,可能確信遷移是一種有用且強大的工具。讓我們開始學習如何使用它。

數據庫遷移的命令

1、根據遷移文件的內容,在數據庫裏生成相應的數據表

  python manage.py migrate  

2、從模型對象的創建數據遷移文件並保存在App的migrations文件夾(執行這條語句在數據庫中不會生成表)

  python manage.py makemigrations 

設置Django項目

在本教程中,將使用一個簡單的比特幣跟蹤器app作爲示例項目。

第一步是安裝Django。 以下是使用虛擬環境在Linux或macOS X上執行此操作的方法:

$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install "Django==2.1.*"
...
Successfully installed Django-2.1.3

現在已經創建了一個新的虛擬環境並將其激活,並在該虛擬環境中安裝了Django。

請注意,在Windows上,將運行env/bin/activate.bat而不是source env/bin/activate來激活虛擬環境。

爲了便於閱讀,控制檯示例將不包括從現在開始的提示的(env)部分。

安裝Django後,可以使用以下命令創建項目:

$ django-admin.py startproject bitcoin_tracker
$ cd bitcoin_tracker
$ python manage.py startapp historical_data

將提供一個簡單的項目和一個名爲historical_data的應用程序。現在這個目錄結構如下:

bitcoin_tracker/
|
├── bitcoin_tracker/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
|
├── historical_data/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations/
│   │   └── __init__.py
|   |
│   ├── models.py
│   ├── tests.py
│   └── views.py
|
└── manage.py

在bitcoin_tracker目錄中,有兩個子目錄:用於項目配置文件的bitcoin_tracker和包含創建的應用程序的文件的historical_data。

現在,要創建模型,請在historical_data/models.py中添加這個類:

class PriceHistory(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    price = models.DecimalField(max_digits=7, decimal_places=2)
    volume = models.PositiveIntegerField()

這是跟蹤比特幣價格的基本模型。

另外,不要忘記將新創建的應用程序添加到settings.INSTALLED_APPS。 打開bitcoin_tracker/settings.py並將historical_data添加到列表INSTALLED_APPS,如下所示:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'historical_data',
]

其他設置適用於此項目。 本教程假定項目配置爲使用SQLite數據庫,這是Django默認的配置。

創建遷移makemigrations

創建了模型之後,需要做的第一件事是爲它創建遷移。可以用以下命令來完成:

$ python manage.py makemigrations historical_data
Migrations for 'historical_data':
  historical_data/migrations/0001_initial.py
    - Create model PriceHistory

注意:指定應用程序的名稱historical_data是可選的。 不指定它會爲所有應用程序創建遷移。

這將生成遷移文件,該文件指示Django如何爲應用程序中定義的模型創建數據庫表。 讓我們再看看目錄樹:

bitcoin_tracker/
|
├── bitcoin_tracker/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
|
├── historical_data/
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   └── __init__.py
|   |
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
|
├── db.sqlite3
└── manage.py

可以看到,migration目錄現在包含一個新文件:0001_initial.py。

注意:可能會注意到運行makemigrations命令還會創建文件db.sqlite3,其中包含SQLite數據庫。
當嘗試訪問不存在的SQLite3數據庫文件時,將自動創建它。
此行爲是SQLite3獨有的。 如果使用任何其他數據庫後端,如PostgreSQL或MySQL,則必須在運行makemigrations之前自己創建數據庫。

可以使用dbshell管理命令查看數據庫。 在SQLite中,列出所有表的命令就是.tables:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
sqlite>

數據庫仍然是空的,因爲還沒有應用遷移。 鍵入.quit以退出SQLite shell。

應用遷移migrate

現在已經創建了遷移,但要實際在數據庫中進行任何更改,必須將其應用於管理命令migrate:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying historical_data.0001_initial... OK
  Applying sessions.0001_initial... OK

根據輸出,遷移已成功應用。 但是所有其他遷移都來自哪裏?

還記得設置INSTALLED_APPS嗎? 其中列出的其他一些應用程序也帶有遷移功能,遷移管理命令默認情況下會爲所有已安裝的應用程序應用遷移。

再看一下數據庫:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
auth_group                    django_admin_log
auth_group_permissions        django_content_type
auth_permission               django_migrations
auth_user                     django_session
auth_user_groups              historical_data_pricehistory
auth_user_user_permissions
sqlite>

現在有多個表。 他們的名字可以瞭解他們的目的。 在上一步中生成的遷移已創建historical_data_pricehistory表。

.schema查看創建表的SQL語句

讓我們使用.schema命令檢查它:

sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory"(
  "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" datetime NOT NULL,
  "price" decimal NOT NULL,
  "volume" integer unsigned NOT NULL
);

.schema命令打印出要爲創建表而執行的CREATE語句。 參數–indent很好地格式化。 即使不熟悉SQL語法,也可以看到historical_data_pricehistory表的模式反映了PriceHistory模型的字段。

每個字段都有一列,主鍵還有一個列ID,除非在模型中明確指定主鍵,否則Django會自動創建。

如果再次運行migrate命令會發生以下情況:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  No migrations to apply.

沒有! Django記得已經應用了哪些遷移,並且不會嘗試重新運行它們。

值得注意的是,還可以將遷移管理命令限制爲單個應用程序:

$ python manage.py migrate historical_data
Operations to perform:
 Apply all migrations: historical_data
Running migrations:
 No migrations to apply.

可以看到,Django現在僅對historical_data應用程序應用遷移。

當第一次運行遷移時,最好應用所有遷移,以確保數據庫包含必要功能所必需的表,例如用戶身份驗證和會話。

改變模型

模型不是一成不變的。 隨着Django項目獲得更多功能,模型將會發生變化。 可以添加或刪除字段或更改其類型和選項。

更改模型的定義時,還必須更改用於存儲這些模型的數據庫表。 如果模型定義與當前數據庫模式不匹配,則很可能會遇到django.db.utils.OperationalError。

那麼如何更改數據庫表? 通過創建和應用遷移。

在測試比特幣跟蹤器時,會發現自己犯了一個錯誤。 人們正在銷售比特幣的分數,因此字段量應爲DecimalField類型而不是PositiveIntegerField。

讓我們將模型更改爲如下所示:

class PriceHistory(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    price = models.DecimalField(max_digits=7, decimal_places=2)
    volume = models.DecimalField(max_digits=7, decimal_places=3)

如果沒有遷移,必須找出SQL語法將PositiveIntegerField轉換爲DecimalField。 幸運的是,Django將處理這個問題。 告訴它進行遷移:

$ python manage.py makemigrations
Migrations for 'historical_data':
  historical_data/migrations/0002_auto_20181112_1950.py
    - Alter field volume on pricehistory

注意:遷移文件的名稱(0002_auto_20181112_1950.py)是基於當前時間的,如果不同系統上遷移的話,名稱會有所不同。

現在將這個遷移應用到數據庫:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  Applying historical_data.0002_auto_20181112_1950... OK

遷移已經成功應用,所以可以使用dbshell驗證更改是否有效果:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory" (
  "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" datetime NOT NULL,
  "price" decimal NOT NULL,
  "volume" decimal NOT NULL
);

如果將新模式與先前看到的模式進行比較,會注意到volume列的類型已從integer更改爲decimal,以反映模型中的Volume字段從PositiveIntegerField更改爲DecimalField。

列出遷移showmigrations

如果想知道Django項目中存在哪些遷移,則無需深入瞭解已安裝應用程序的遷移目錄。 可以使用showmigrations命令:

$ ./manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
historical_data
 [X] 0001_initial
 [X] 0002_auto_20181112_1950
sessions
 [X] 0001_initial

這將列出項目中的所有應用程序以及與每個應用程序關聯的遷移。 此外,它將在已經應用的遷移旁邊放置一個大X。

對於這個示例,showmigrations命令並不是特別令人興奮,但是當開始處理現有代碼庫,或在不是唯一添加遷移的團隊中工作時它會派上用場,因爲它可以看到團隊中用的哪些文件已經應用過了。

取消應用遷移migrate <name>

現在,已瞭解如何通過創建和應用遷移來更改數據庫模式。 在某些時候,可能希望撤消更改並切換回早期的數據庫模式,因爲:

  • 想要測試一位同事寫的遷移
  • 意識到所做的更改有問題
  • 同時處理具有不同數據庫更改的多個功能
  • 想要還原在數據庫仍具有較舊架構時創建的備份

幸運的是,遷移不一定是不可逆的。 在許多情況下,遷移的影響可以通過取消遷移來撤消。 要取消應用遷移,必須在要取消應用的遷移之前使用應用程序名稱和遷移名稱調用migrate。

如果要在historical_data應用程序中還原遷移0002_auto_20181112_1950,則必須將0001_initial作爲參數傳遞給migrate命令:

$ python manage.py migrate historical_data 0001_initial
Operations to perform:
  Target specific migration: 0001_initial, from historical_data
Running migrations:
  Rendering model states... DONE
  Unapplying historical_data.0002_auto_20181112_1950... OK

可以看到遷移未應用,這意味着對數據庫的更改已被撤消。

取消應用遷移不會刪除其遷移文件。 下次運行migrate命令時,將再次應用遷移。

警告:不要將未應用的遷移與最常用的文本編輯器中的撤消操作混淆。
並非所有數據庫操作都可以完全還原。 如果從模型中刪除字段,創建遷移並應用它,Django將從數據庫中刪除相應的列。
取消應用遷移將重新創建列,但它不會帶回存儲在該列中的數據!

當處理遷移名稱時,Django會通過不強制拼出遷移的全名來節省一些按鍵。 它只需要足夠的名稱來識別它。

在前面的示例中,運行python manage.py migrate history_data 0001就足夠了。

命名遷移–name

在上面的示例中,Django根據時間戳提出了遷移名稱 - 類似於*0002_auto_20181112_1950。 如果對此不滿意,則可以使用–name參數提供自定義名稱(不帶.py擴展名)。

要試一試,首先必須刪除舊的遷移。 已經取消應用它,因此可以安全地刪除該文件:

$ rm historical_data/migrations/0002_auto_20181112_1950.py

現在可以用一個更具描述性的名字重新創建它:

$ ./manage.py makemigrations historical_data --name switch_to_decimals

這將創建與之前相同的遷移,只不過新名稱爲0002_switch_to_decimals

結論

在本教程中介紹了相當多的內容,並學習了Django遷移的基礎知識。

回顧一下,使用Django遷移的基本步驟如下所示:

創建或更新模型
運行./manage.py makemigrations <app_name>
運行./manage.py migrate以遷移所有內容或./manage.py migrate <app_name>以遷移單個應用程序
必要時重複而已! 此工作流程在大多數情況下都可以工作,但如果流程沒有按預期進行,還知道如何列出和取消應用遷移。

如果以前使用手寫SQL創建和修改了數據庫表,那麼通過將此工作委派給Django遷移,現在可以提高效率。

在本系列的下一個教程中,將深入瞭解該主題並瞭解Django Migrations如何在底層工作。

Django遷移:深入

上面我們討論了使用新的Django遷移系統的基礎知識。

當流程無法正常工作時會發生什麼? 好吧,那時可能不得不去檢查以前的遷移,試圖弄清楚發生了什麼。 爲了幫助解決這個問題,讓我們深入瞭解一下,以便更好地瞭解遷移的工作原理。

遷移時如何知道要遷移的內容

試試這個。 從bitcoin_tracker應用程序再次運行遷移(./manage.py migrate)。 怎麼了? 沒有。 而這正是重點。

默認情況下,Django永遠不會在同一個數據庫上多次運行遷移。 這由一個名爲django_migrations的表管理,該表在第一次運行遷移時在數據庫中創建。 對於每次運行或僞造的遷移,都會在表中插入一個新行。

例如,以下是運行初始遷移後表的數據:

ID app name applied
1 historical_payments 0001_initial 2014-04-16 14:12:30.839899+08

很有趣,因爲只有一次遷移,但每次後續遷移都會添加新行。

下次運行遷移時,它將跳過數據庫表中列出的遷移文件。這意味着即使手動更改遷移文件,如果數據庫中已存在該條目,也會跳過該文件。

這是有道理的,因爲通常不希望兩次運行遷移。但是如果做了什麼原因,讓它再次運行的一種方法是首先從數據庫中刪除相應的行(注意這不是“官方推薦的方式”,但它會起作用)。在第一次運行遷移時從South升級的情況下,Django將首先檢查數據庫結構,如果它與遷移相同(即遷移不應用任何新的更改),那麼遷移將是“僞造“意思不是真的運行,但django_migrations表仍將更新。

相反,如果要“撤消”特定應用程序的所有遷移,可以遷移到名爲zero的特殊遷移。

例如,如果鍵入:

$ ./manage.py migrate historical_data zero

它將撤消historical_data應用程序的所有遷移。 除了使用zero;也可以使用任意遷移名稱,如果該遷移過去,則數據庫將回滾到該遷移的狀態,或者如果尚未運行遷移則前滾。 相當強大的東西!

遷移文件

如何創建實際的遷移文件? 換句話說,運行./manage.py makemigrations <appname>時會發生什麼?

Django遷移實際上是創建一個遷移文件,該文件描述瞭如何在數據庫中創建適當的表。 實際上,可以查看已創建的遷移文件。 別擔心:這只是Python類型的文件。

不要忘記git添加新的遷移目錄,以便它受版本控制。

historical_prices應用程序現在將有一個名爲/migrations的子目錄,其中該應用程序的所有遷移文件都將保存在該目錄中。 我們來看看historical_data/migrations/0001_initial.py,因爲這是創建初始遷移代碼的文件。 它看起來應該類似於:

# encoding: utf8
from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='PriceHistory',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),
                ('date', models.DateTimeField(auto_now_add=True)),
                ('price', models.DecimalField(decimal_places=2, max_digits=5)),
                ('volume', models.PositiveIntegerField()),
                ('total_btc', models.PositiveIntegerField()),
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

要使遷移工作,必須創建一個名爲Migration()的類,該類繼承自django.db.migrations.Migration。 這是遷移框架在我們要求它運行遷移時將查找並執行的類(我們稍後會這樣做)。

Migration類包含兩個主要列表,依賴項dependencies和操作operations。

遷移依賴項

dependencies對象是在運行此遷移之前必須運行的遷移列表。

在上面的情況下,沒有必須先運行,所以沒有依賴。 但是,如果有外鍵關係,那麼必須確保在向其添加外鍵之前創建模型。 所以我們假設我們有另一個名爲main的應用程序,它定義了我們想要在外鍵中引用的表。 然後我們的依賴項列表可能如下所示:

dependencies = [
   ('main', '__first__'),
]

上面的依賴關係表明必須首先運行main應用程序的遷移。

還可以依賴於特定文件,如下所示:

dependencies = [
    ('main', '0001_initial'),
]

這是來自main應用程序的名爲0001_initial的文件的依賴項。

依賴關係也可以組合在一起,因此可以擁有多個依賴關係。 此功能提供了很大的靈活性,因爲可以容納依賴於不同應用程序模型的外鍵。 這也意味着遷移的編號(通常是0001,0002,0003,…)並不一定嚴格按照它們的應用順序排列。 可以添加所需的任何依賴項,從而控制順序,而無需重新編號所有遷移。

遷移操作

Migration()類中的第二個列表是operations列表。 這是要作爲遷移的一部分應用的操作列表。 通常,操作可以屬於以下類型之一:

CreateModel:你猜對了:這會創建一個新模型。 有關示例,請參閱上面的遷移。
DeleteModel:從數據庫中刪除一個表; 只需傳入模型的名稱。
RenameModel:給定old_name和new_name,這將重命名模型。
AlterModelTable:更改與模型關聯的表的名稱。 與db_table選項相同。
AlterUniqueTogether:更改唯一約束。
AlteIndexTogether:更改模型的自定義索引集。
AddField:就像聽起來一樣。 這是一個例子:

migrations.AddField(
    model_name='PriceHistory',
    name='market_cap',
    field=models.PositiveIntegerField(),
),

RemoveField:我們不再需要那個字段…只需刪除它即可。
RenameField:給定model_name,old_name和new_name,這會將old_name字段更改爲new_name。
還有一些“特殊”操作:

RunSQL:這允許傳入原始SQL並將其作爲模型的一部分執行。
RunPython:傳入一個要執行的可調用函數;對於像遷移這樣的數據加載之類的東西很有用。
甚至可以編寫自己的操作。 通常,當運行makemigrations時,Django將使用需要的相應依賴項和操作創建必要的遷移。 但是,瞭解遷移文件本身及其工作原理可提供更大的靈活性。

示例
讓我們對模型再做一些修改,看看對遷移的影響:

class PriceHistory(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    # Bitcoin to the moon (we need more digits)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    volume = models.PositiveIntegerField()
    total_btc = models.PositiveIntegerField()
    market_cap = models.PositiveIntegerField(null=True)

由於看好比特幣,我們已經決定在價格領域需要更多的數字,我們還決定跟蹤市值。 請注意我們如何使market_cap字段可以爲空。 如果我們沒有,遷移將要求爲所有現有行提供值(就像South一樣):

You are trying to add a non-nullable field 'market_cap' to PriceHistory without a default;
we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py

現在再次運行./ management .py makmigration將生成一個新的遷移文件0002_auto_<date_time_stamp>。

請記住,可以使用./manage.py makemigrations --name <some name>爲遷移創建自定義名稱

該文件應該是這樣的:

class Migration(migrations.Migration):

    dependencies = [
        ('historical_data', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='PriceHistory',
            name='market_cap',
            field=models.PositiveIntegerField(null=True),
            preserve_default=True,
        ),
        migrations.AlterField(
            model_name='PriceHistory',
            name='price',
            field=models.DecimalField(max_digits=8, decimal_places=2),
        ),
    ]

請注意dependencies列表,該列表聲明我們必須在運行此遷移之前運行初始遷移。 此遷移還有兩個操作 - AddField,它創建我們新添加的market_cap,以及AlterField,它更新我們的價格字段的max_digits。

重要的是要理解這些操作只調用遷移框架,該框架處理對settings.py文件中定義的數據庫執行各種操作。

開箱即用的遷移支持Django支持的所有標準數據庫。 因此,如果堅持dependencies項部分中列出的原語,可以手動創建所需的任何遷移,而無需擔心底層SQL。 這一切都是爲我們完成的。

查看遷移

即使不需要擔心遷移生成的SQL,如果很好奇,Django已經爲我們做好了準備——只需運行:

$ ./manage.py sqlmigration <app-name> <migration-name>

這樣做將根據settings.py文件中的數據庫列出將由指定的遷移生成的基礎SQL好奇。 運行這幾次,將真正開始欣賞遷移的力量!

結論

我們已經到達了另一個終點,但還有一個起點。在上一篇文章中,我們將討論數據遷移。乾杯!

數據遷移

再次回來。

遷移主要用於使數據庫的數據模型保持最新,但數據庫不僅僅是數據模型。 最值得注意的是,它也是一大堆數據。 因此,如果不討論數據遷移,任何關於數據庫遷移的討論都是不完整的。

數據遷移定義

數據遷移在許多場景中使用。 兩個非常受歡迎的是:

  • 當希望加載應用程序所依賴的“系統數據”以成功運行時。
  • 當對數據模型的更改強制需要更改現有數據時。

請注意,加載用於測試的虛擬數據不在上面的列表中。 可以使用遷移來執行此操作,但遷移通常在生產服務器上運行,因此可能不希望在生產服務器上創建一堆虛擬測試數據。

示例:
繼續之前的Django項目,作爲創建一些“系統數據”的一個例子,讓我們創建一些歷史比特幣價格。 Django遷移將幫助我們,通過創建一個空的遷移文件並將其放在正確的位置,如果我們鍵入:

$ ./manage.py makemigrations --empty historical_data

這應該創建一個名爲historical_data/migrations/003_auto<date_time_stamp>.py的文件。 我們將名稱更改爲003_load_historical_data.py,然後將其打開。 將擁有一個默認結構,如下所示:

# encoding: utf8
from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
        ('historical_data', '0002_auto_20140710_0810'),
    ]

    operations = [
    ]

可以看到它爲我們創建了一個基礎結構,甚至插入了依賴項。 這很有幫助。 現在要進行一些數據遷移,請使用RunPython遷移操作:

# encoding: utf8
from django.db import models, migrations
from datetime import date

def load_data(apps, schema_editor):
    PriceHistory = apps.get_model("historical_data", "PriceHistory")

    PriceHistory(date=date(2013,11,29),
         price=1234.00,
         volume=354564,
         total_btc=12054375,
         ).save()
    PriceHistory(date=date(2012,11,29),
         price=12.15,
         volume=187947,
         total_btc=10504650,
         ).save()


class Migration(migrations.Migration):

    dependencies = [
        ('historical_data', '0002_auto_20140710_0810'),
    ]

    operations = [
        migrations.RunPython(load_data)
    ]

我們首先定義函數load_data - 猜對了 - 加載數據。

對於一個真正的應用程序,我們可能想要訪問blockchain.info並獲取完整的歷史價格列表,但我們只是在那裏放了幾個來展示遷移的工作原理。

一旦我們有了這個函數,我們可以從RunPython操作中調用它,然後當我們從命令行運行./manage.py migrate時,將執行這個函數。

記下這條線:

PriceHistory = apps.get_model("historical_data", "PriceHistory")

在運行遷移時,獲取所在遷移點相對應的PriceHistory模型版本非常重要。在運行遷移時,模型(PriceHistory)可能會更改,例如,在後續遷移中添加或刪除列。這可能會導致數據遷移失敗,除非使用上面的行來獲取正確的模型版本。有關這方面的更多信息,請參閱此處的評論。

這可能比運行syncdb並讓它加載一個fixture更有用。事實上,遷移不尊重fixtures - 這意味着他們不會像syncdb那樣自動加載它們。

這主要歸功於哲學。

雖然可以使用遷移來加載數據,但它們主要是關於遷移數據和/或數據模型。我們已經展示了加載系統數據的示例,主要是因爲它是如何設置數據遷移的簡單說明,但數據遷移通常用於更復雜的操作,例如轉換數據以匹配新數據模型。

一個例子可能是如果我們決定開始存儲多個交易所的價格而不是一個,所以我們可以添加price_gox,price_btc等字段,然後我們可以使用遷移將所有數據從price列移動到price_btc列。

通常,在處理Django 1.7中的遷移時,最好將數據加載爲遷移數據庫的單獨練習。如果確實想繼續使用/加載fixture,可以使用如下命令:

$ ./manage.py loaddata historical_data/fixtures/initial_data.json

這會將數據從fixture加載到數據庫中。

這不會像數據遷移那樣自動發生(這可能是一件好事),但功能仍然存在;它沒有丟失,所以如果有需要,請隨時繼續使用fixtures。不同的是,現在需要時使用fixtures加載數據。如果使用fixtures加載單元測試的測試數據,請記住這一點。

結論

這與前兩篇文章一起介紹了使用遷移時遇到的最常見方案。還有很多場景,如果很好奇並且真的想深入瞭解遷移,那麼最好的去處(代碼本身除外)就是官方文檔。

請記住,在一般情況下,正在處理:

架構遷移:更改數據庫或表的結構而不更改數據。這是最常見的類型,Django通常可以自動爲我們創建這些遷移。
數據遷移:對數據的更改或加載新數據。 Django無法爲我們生成這些。必須使用RunPython遷移手動創建它們。
因此,選擇適合我們的遷移,運行makemigrations,然後確保每次更新模型時都更新遷移文件 - 這或多或少都是如此。這將允許將我們的遷移與代碼一起保存在git中,並確保可以更新數據庫結構而不必丟失數據。

快樂遷移!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章