今すぐ見るこのチュートリアルには、RealPythonチームによって作成された関連するビデオコースがあります。書かれたチュートリアルと一緒にそれを見て、理解を深めてください: Django Migrations 101
バージョン1.7以降、Djangoにはデータベース移行のサポートが組み込まれています。 Djangoでは、データベースの移行は通常、モデルと密接に関連しています。新しいモデルをコーディングするたびに、データベースに必要なテーブルを作成するための移行も生成します。ただし、移行によってさらに多くのことが可能になります。
Django Migrationsがどのように機能し、4つの記事と1つのビデオでそれらを最大限に活用する方法を学びます:
- パート1:Djangoの移行:入門書(現在の記事)
- パート2:移行を深く掘り下げる
- パート3:データ移行
- ビデオ:Django1.7の移行-入門書
この記事では、Djangoの移行に慣れ、次のことを学びます。
- SQLを記述せずにデータベーステーブルを作成する方法
- モデルを変更した後にデータベースを自動的に変更する方法
- データベースに加えられた変更を元に戻す方法
無料ボーナス: ここをクリックして、無料のDjangoラーニングリソースガイド(PDF)にアクセスします。このガイドには、Python +DjangoWebアプリケーションを構築する際に避けるべきヒントとコツおよび一般的な落とし穴が示されています。
移行によって解決される問題
Djangoまたは一般的なWeb開発に慣れていない場合は、データベース移行の概念に精通していない可能性があり、なぜそれらが優れたアイデアであるかが明らかでないように思われるかもしれません。
まず、全員が同じページにいることを確認するために、いくつかの用語を簡単に定義しましょう。 Djangoは、PostgreSQL、MySQL、SQLiteなどのリレーショナルデータベース管理システムに格納されているリレーショナルデータベースと連携するように設計されています。
リレーショナルデータベースでは、データはテーブルに編成されています。データベーステーブルには特定の数の列がありますが、任意の数の行を含めることができます。各列には、特定の最大長の文字列や正の整数など、特定のデータ型があります。すべてのテーブルとその列およびそれぞれのデータ型の記述は、データベーススキーマと呼ばれます。
Djangoでサポートされているすべてのデータベースシステムは、SQL言語を使用して、リレーショナルデータベースのデータを作成、読み取り、更新、および削除します。 SQLは、データベーステーブル自体の作成、変更、および削除にも使用されます。
SQLを直接操作するのは非常に面倒な場合があるため、作業を楽にするために、Djangoにはオブジェクトリレーショナルマッパー(略してORM)が付属しています。 ORMは、リレーショナルデータベースをオブジェクト指向プログラミングの世界にマッピングします。 SQLでデータベーステーブルを定義する代わりに、PythonでDjangoモデルを記述します。モデルは、データベーステーブルの列に対応するデータベースフィールドを定義します。
Djangoモデルクラスをデータベーステーブルにマッピングする方法の例を次に示します。
しかし、Pythonファイルでモデルクラスを定義するだけでは、データベーステーブルが魔法のようにどこからともなく現れるわけではありません。 Djangoモデルを保存するデータベーステーブルを作成するのは、データベース移行の仕事です。さらに、フィールドの追加など、モデルに変更を加えるたびに、データベースも変更する必要があります。移行もそれを処理します。
Djangoの移行によってあなたの生活が楽になるいくつかの方法があります。
SQLを使用せずにデータベースを変更する
移行しない場合は、データベースに接続して一連のSQLコマンドを入力するか、PHPMyAdminなどのグラフィカルツールを使用して、モデル定義を変更するたびにデータベーススキーマを変更する必要があります。
Djangoでは、移行は主にPythonで記述されているため、実際に高度なユースケースがない限り、SQLを知る必要はありません。
繰り返しの回避
モデルを作成してからSQLを記述して、そのデータベーステーブルを作成するのは繰り返しになります。
移行はモデルから生成されるため、繰り返さないようにしてください。
モデル定義とデータベーススキーマの同期の確保
通常、データベースには複数のインスタンスがあります。たとえば、チーム内の開発者ごとに1つのデータベース、テスト用のデータベース、ライブデータを含むデータベースなどです。
移行しない場合は、データベースごとにスキーマの変更を実行する必要があります。また、どのデータベースに対してどの変更が既に行われたかを追跡する必要があります。
Django Migrationsを使用すると、複数のデータベースをモデルと簡単に同期させることができます。
バージョン管理におけるデータベーススキーマの変更の追跡
Gitのようなバージョン管理システムはコードには優れていますが、データベーススキーマにはそれほど優れていません。
移行はDjangoのプレーンなPythonであるため、他のコードと同じようにバージョン管理システムに配置できます。
これまでに、移行が便利で強力なツールであると確信していることを願っています。その力を解き放つ方法を学び始めましょう。
Djangoプロジェクトのセットアップ
このチュートリアル全体を通して、サンプルプロジェクトとして単純なビットコイントラッカーアプリで作業します。
最初のステップはDjangoをインストールすることです。仮想環境を使用してLinuxまたはmacOSXでこれを行う方法は次のとおりです。
$ 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
内 ディレクトリには、2つのサブディレクトリがあります: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データベースを使用するように構成されていることを前提としています。
移行の作成
モデルを作成したら、最初にそのモデルの移行を作成する必要があります。これは、次のコマンドで実行できます。
$ 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
ご覧のとおり、migrations
ディレクトリに新しいファイルが含まれるようになりました: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シェルを終了します。
移行の適用
これで移行が作成されましたが、データベースに実際に変更を加えるには、管理コマンド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
の設定を覚えておいてください ?そこにリストされている他のアプリのいくつかにも移行が付属しており、migrate
管理コマンドは、デフォルトでインストールされているすべてのアプリに移行を適用します。
データベースをもう一度見てください:
$ 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
を使用して調べてみましょう コマンド:
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は、どの移行がすでに適用されているかを記憶しており、それらを再実行しようとはしません。
migrate
を制限することもできることに注意してください。 単一のアプリへの管理コマンド:
$ 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
に遭遇する可能性があります。 。
では、データベーステーブルをどのように変更しますか?移行を作成して適用する。
ビットコイントラッカーをテストしていると、間違いを犯したことに気づきます。人々はビットコインの一部を販売しているので、フィールドvolume
タイプは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)
移行しない場合は、PositiveIntegerField
を有効にするためにSQL構文を理解する必要があります。 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
へ 。
移行の一覧表示
Djangoプロジェクトにどのような移行が存在するかを知りたい場合は、migrations
を掘り下げる必要はありません。 インストールしたアプリのディレクトリ。 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
を呼び出す必要があります アプリの名前と移行の名前before 適用を解除する移行。
移行を元に戻したい場合0002_auto_20181112_1950
historical_data
で アプリの場合、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 historical_data 0001
を実行するだけで十分でした。 。
名前の移行
上記の例では、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の移行に委任することで、はるかに効率的になりました。
このシリーズの次のチュートリアルでは、トピックをさらに深く掘り下げて、DjangoMigrationsが内部でどのように機能するかを学びます。
無料ボーナス: ここをクリックして、無料のDjangoラーニングリソースガイド(PDF)にアクセスします。このガイドには、Python +DjangoWebアプリケーションを構築する際に避けるべきヒントとコツおよび一般的な落とし穴が示されています。
乾杯!