Djangoフレームワークを利用してウェブアプリケーションを作るのは大変便利です。MVCモデルを例えるとすれば、ModelとViewの部分で煩雑なディテールを実装してくれて、プログラマーがやりたいこと(Control)に集中できるように手助けしています。
今回では、Modelの部分に関連するmigrationsに関して記載したいと思います。DjangoのProjectの作成設定周りはDjangoオフィシャルチュートリアルを参考し、migrationsあたりはこちらを参考しています。
migrationsとは
日本語に翻訳すると、migrationsは「移行」を意味しています。Djangoでは、主にユーザーが設計したデータ構造を自動的にデータベースのスキーマに変更する機能を指しています(マニュアルでmigrationsファイルを書くことも可能ですが、機会があればまた紹介します)。
まず使ってみましょう
チュートリアルを参考しながら、アプリを作りましょう(ただし、データモデル部分だけ)。
開発環境 |
---|
Mac OS:Sierra |
python2.7.10 |
django1.11.2 |
mysql5.7.18 |
workingディレクトリに入って、ターミナルで下記コマンドを入力:
django-admin startproject m_Migration
python manage.py startapp polls
これでプロジェクトm_Migration及び中にpollsアプリを作成しました。
次にデータベースを設定します。デフォルトのsqliteではなく、mysqlを使用しますので、
プロジェクトをsettingsファイルを変更する必要があります。
Djangoのデータベースの設定
- mysqlを立ち上げ、ユーザーとユーザーのパスワードと今回使用するデータベースを作成します。
- 1で作成した属性に対応して、プロジェクトパッケージにあるsettings.pyを変更する(詳細はこちら参照)。
python:settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'blog',
'USER':'user',
'PASSWORD':'',
'HOST':'',
'PORT':'3306',
}
}
あとはターミナルで初期設定を反映します。
python manage.py migrate
ログ:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, 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 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 sessions.0001_initial... OK
mysqlクライアントに入り、データベースblog現在持ってるテーブルを見てみると:
+----------------------------+
| Tables_in_blog |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
フレームワーク関連のデータベースが作成されました。
現時点model.pyモジュールを持ってるのはpollsアプリだけなので、pollsパッケージでmigrationsフォルダーが作成されされました。
モデルを作成しましょう
pollsアプリで使うデータモデルCategoryとArticleを作成します。
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
text = models.CharField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
pollsアプリの機能は保存してあるブログの記事を表示することです。したがって、記事モデルArticleと記事のジャンルを示すCategoryモデルを作成しました。作成したモデルを反映する為に、まずオペレーションを記述したmigrationsファイルを作成します。
python manage.py makemigrations polls
ログ:
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Article
- Create model Category
- Add field category to article
ここで、migrations/フォルダーでは今回model.pyへの変更を記録したmigrationsファイル0001_initial.pyを作成しました。
次に、作成したmigrationsファイルを反映させます
python manage.py migrate
ログ:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
今データベースでは
+----------------------------+
| Tables_in_blog |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
| polls_article |
| polls_category |
+----------------------------+
テーブルのスキーマを見てみると:
mysql>DESC polls_article;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(100) | NO | | NULL | |
| text | varchar(1000) | NO | | NULL | |
| category_id | int(11) | NO | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
mysql>DESC polls_category;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
モデル通りに、新たにpollsアプリのテーブル(polls_article、polls_category)が作成されました(idフィールドはデフォルトで自動作成されます)。ここまでが、アプリでモデルを設計し、djangoのmigrations機能を利用してデータベースを作成する流れです。
よくある利用ケース
一度作成してから、新機能の追加など、データモデルを修正する場合もあります。
データモデルの更新
pollsアプリを例とします。例えば、もともとのブログサービスでは文字だけの記事を提供しましたが、いいデジカメを購入したので、up主が記事に写真をつけたいと思うようになりました。ここで、Articleモデルに写真のurlを保存するフィールドimage_urlを追加しましょう(すでにあるレコードのためにデフォルト値も設定します)。
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
text = models.CharField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image_url = models.URLField(max_length=200, default='toBeImplement')
変更を記録しましょう
python manage.py makemigrations polls
ログ:
Migrations for 'polls':
polls/migrations/0002_article_image_url.py
- Add field image_url to article
新しいmigrationsファイル0002_article_image_url.pyが作成されました。
変更を反映させます。
python manage.py migrate
データベース現在のスキーマを見て見ましょう:
DESC polls_article;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(100) | NO | | NULL | |
| text | varchar(1000) | NO | | NULL | |
| category_id | int(11) | NO | MUL | NULL | |
| image_url | varchar(200) | NO | | NULL | |
+-------------+---------------+------+-----+---------+----------------+
計画通りに、データベースを更新できました。
データモデルの復旧
gitなどVCSのように、データモデルのバージョンをコントロールすることもできます。この機能の活躍場面として、緊急事態でのデータモデルの復旧が挙げられます。
仮に上記の例で写真urlに関連する変更を行い、migrationsファイル0002_article_image_url.pyが作成された状態でmigrateコマンドを実行しました。
python manage.py migrate
ここでmigrateが失敗しました。最新のmigrationsの状態が0002_article_image_url.pyであり、しかし実際データベースのスキーマは0001_initial.pyに対応しています。この状態ではテーブルに写真urlに対応するコラムがありません。pollsアプリから写真urlデータをアクセスしようとしたらエラーが出ます。この問題の1つの対応策として、migrationsの状態を0001_initial.pyに復旧するが挙げられます(それからバッグを探します)。
復旧するために、同じくmigrateコマンドを利用して、migrationsファイル0001_initial.pyが記録した状態まで復旧します。
python manage.py migrate polls 0001_initial
ログ:
Operations to perform:
Target specific migration: 0001_initial, from polls
Running migrations:
Rendering model states... DONE
Unapplying polls.0002_article_image_url... OK
ログが示したように、0002_article_image_url.pyの変更が撤廃(unapply)されました。今のArticleのテーブルのスキーマを見て見ましょう:
DESC polls_article;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(100) | NO | | NULL | |
| text | varchar(1000) | NO | | NULL | |
| category_id | int(11) | NO | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
テーブルが元の状態に戻りました。