PyramidでToDo管理サービスを作る 【DBマイグレーション】
データベースを使用するためのプロジェクトもできたことだし、これからToDo管理サービスで使うモデルを作成していこうと思う。
実行環境
- Windows 8.1 (まだ10にしていない)
- Python 3.4.3
- Pyramid 1.5.7
モデルを作る
ToDoManager/todomanager/models.py
にscaffold時に作成されたデフォルトのモデルが設定されている。
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
name = Column(Text)
value = Column(Integer)
Index('my_index', MyModel.name, unique=True, mysql_length=255)
今回は不要なので削除しつつ、必要となるモデルを追加していく。
取り敢えずユーザ情報とかは後回しにして、ToDoを管理するためのモデルを作成する。
テーブル定義
ひとまずは必要最低限のものに絞ってリストアップする。
- ToDo情報
- ID
- ToDo内容
- 登録日
- 更新日
上の内容をコードにするとこんな感じになる。
必要な import
は物を適宜追加する。
class Task(Base):
__tablename__ = 'tasks'
id = Column(Integer, primary_key=True)
summary = Column(Text)
created_at = Column(DateTime, default=datetime.datetime.now())
updated_at = Column()
DB初期化用のファイル script/initializedb.py
には先ほど削除した MyModel
が残っているため該当部分を削除する。
また、初期値として登録するものはないためその部分も削除する。
from ..models import (
DBSession,
MyModel, <- 削除する
Base,
)
def main(argv=sys.argv):
(省略)
with transaction.manager:
model = MyModel(name='one', value=1) <- 削除する
DBSession.add(model) <- 削除する
pass <- 追加する
データベースのマイグレーション
alembicのインストール
Djangoとは異なり、マイグレーションをするに辺りそれ用のモジュールをインストールする必要があるらしい。
マイグレーション用モジュールとして alembic
をインストールする。
(pyramid_python)> pip install alembic
インストール後の pip list
は以下のようになる。
特にバージョン番号を指定していないから、インストールする度にバージョン番号が変わる。
(pyramid_python)> pip list
alembic (0.8.2)
chameleon (2.22)
mako (1.0.1)
markupsafe (0.23)
PasteDeploy (1.5.2)
pip (7.1.2)
pygments (2.0.2)
pyramid (1.5.7)
pyramid-chameleon (0.3)
pyramid-debugtoolbar (2.4)
pyramid-mako (1.0.2)
pyramid-tm (0.12)
python-editor (0.4)
repoze.lru (0.6)
setuptools (12.0.5)
sqlalchemy (1.0.8)
ToDoManager (0.0, e:\developments\pycharmprojects\todomanager\todomanager)
transaction (1.4.4)
translationstring (1.3)
venusian (1.0)
waitress (0.8.9)
WebOb (1.4.1)
zope.deprecation (4.1.2)
zope.interface (4.1.2)
zope.sqlalchemy (0.7.6)
alembic
を使うために次のコマンドで初期化する。
(pyramid_python)> alembic init alembic
こんな感じのログが出力されて必要なファイルが生成される。
Creating directory E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic ... done
Creating directory E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\versions ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic.ini ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\env.py ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\README ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\script.py.mako ... done
Please edit configuration/connection/logging settings in 'E:\\Developments\\PycharmProjects\\ToDoManager\\ToDoManager\\alembic.ini' before proceeding.
alembicの設定
生成された alembic.ini
の sqlalchemy.url
を変更する。
今はSQLiteを使用しているので以下のように書き換える。
sqlalchemy.url = driver://user:pass@localhost/dbname
↓
sqlalchemy.url = sqlite:///%(here)s/ToDoManager.sqlite
サーバを起動させるために作成したテーブルなどを一度削除する。
SQLiteなので今回は手っ取り早く ToDoManager.sqlite
ファイルを削除する。
alembic/env.py
の#add your model's MetaData object here
とコメントが書かれている辺りに次のコードを追記する。
from todomanager.models import Base
target_metadata = Base.metadata
マイグレーションファイルの生成
テーブルの状態と models.py
の差分で自動的にマイグレーションファイルを生成するモードがあるのでそれを利用する。
(pyramid_python)> alembic revision --autogenerate -m "Create Task model"
こんな感じのログが出力されて、マイグレーションに必要なファイルが生成される。
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'tasks'
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\versions\809bd8fbc9_create_task_model.py ... done
生成されたマイグレーションファイルファイルはこんな感じになる。
リビジョン番号は、マイグレーションファイルを識別するためのコードのため、ファイルを生成する度に異なる。
# revision identifiers, used by Alembic.
revision = '809bd8fbc9'
down_revision = None
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.create_table('tasks',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('summary', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table('tasks')
### end Alembic commands ###
ドキュメントを見ると、マイグレーションファイルの自動生成する際に、変更を検知できる項目とできない項目があるらしい。
変更を検知できるもの
- テーブルの追加と削除
- カラムの追加と削除
- カラムのnullステータス
- インデックスやユニーク制約などの基本的な変更
- 外部参照キーの基本的な変更
変更を検知できないもの
- テーブル名の変更
- カラム名の変更
- 無名のインデックスなど
詳細はここ Auto Generating Migrations で確認できる。
マイグレーションの実行
生成されたマイグレーションファイルを使用してデータベースのマイグレーションをする。
状態を確認する
alembic current
コマンドを入力して状態を確認する。(pyramid_python)> alembic current INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL.
マイグレーションを実行する
alembic upgrade header
コマンドでマイグレーションを実行する。(pyramid_python)> alembic upgrade head INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running upgrade -> 809bd8fbc9, Create Task model
upgrade
には、リビジョン番号
かhead
が指定できる。 それ外にも+N
表記でも可能らしい。マイグレーションの実行を取り消す
alembic downgrade -1
コマンドでマイグレーションを取り消せる。(pyramid_python)> alembic downgrade -1 INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running downgrade 809bd8fbc9 -> , Create Task model
downgrade
には、リビジョン番号
か-N
が指定できる。マイグレーションの履歴を確認する
alembic history
コマンドでマイグレーションの履歴を確認できる。(pyramid_python)> alembic history <base> -> 809bd8fbc9 (head), Create Task model
(追記)
上記の変更を反映したコードをコミット。
view.py
について変更し忘れていたため、修正したコミット。