前回の続き↓
[Python]AWS + Tornadoの環境構築
・AWSのEC2とRDSを使ってインフラ構築
・EC2のOSはAmazon Linux
・RDSのDBMSにはMySQL
・サーバ側はPython3
・DBのORMにはsqlalchemy
・マイグレーションにはalembic
・コーディング規約はpycodestyle(pep8)
こんな感じのチャットアプリを作ろうと思います。

参考
Python の Alembic を使って RDB のスキーマを管理する
↓やることはほぼこれです。
Alembicでマイグレーションスクリプトを自動生成する最小限の設定

環境設定

Alembicを使います
モデルを別で書きたかったので、meta_dataを使う形式にしてみます。

pip install alembic
pip freeze | grep alembic
>alembic==0.9.6

migrationの下準備

alembic init migrations #migrationsフォルダが作成される
vi alembic.ini 
alembic.ini
sql_alchemy.url=DBへのパス
#パスの書き方は後述

今回はモデルを別ファイルで定義することにしたので、models.pyをmigrationsディレクトリと同じ階層に作る。

models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False)

    def __repr__(self):
        return "<User(name='%s')>" % (self.name)

migrations/env.pyでこのmodelsをインポートする。

env.py
import models
target_metadata = models.Base.metadata
#target_metadata = None

これで下準備は完了なのでmigrationすればいいはず…

alembic revision --autogenerate -m "Add account table"

するとエラー

ERROR [alembic.util.messaging] Target database is not up to date.
  FAILED: Target database is not up to date.

stackflowを見て(ここには書いてないけど)、どうやらalembic.iniのscript_locationが間違ってたみたい。エラーですぎていろいろいじっていたからずれてしまっていた。
一応参考↓
Error when autogenerate migration scripts with alembic

alembic.ini
script_location = migrations #←作ったフォルダ名

これでmigrationしてみる。

alembic revision --autogenerate -m "Init tables"
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'users'

うまくいったみたい。migrations/versions直下にマイグレーションファイルができている。
あとはalembic upgrade headすればよい!

さっそくするとDBのパスが間違っていることが判明。

sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")

のようなエラーが出てきた。
localhost(この場合ec2インスタンス)からDBに繋げないらしい。
mysql -u root -p -h エンドポイント名  なら繋げてるのに…

下のURLを見てみたけれどRDSを使わずにMySQLを使っているので関係なさそう。(一応やった)
EC2にMySQLインストールと設定確認
後から見返したら全く不要な作業だったと思う。

調べてみると、alembic.iniのsqlalchemy.urlが理解できていなかったみたい。
構造は sqlalchemy.url = driver://user:pass@host/dbname

driver: DBMS名+ライブラリ名、何を使ってDBにアクセスするか
user: DBのユーザー名、RDSの設定をしていればインスタンスページに書いてある
pass: RDS設定時に決めたパスワード
host: DBのホスト名、今回はec2内でmysqlを稼働させるのではなく、RDSを使いたいのでRDSのホスト名(つまりエンドポイント)
dbname: 接続するDBの名前、わからなければRDSに直接接続してshow databasesすれば確認できると思う

自分の場合はMySQLを触るためのライブラリを入れていなかったことが判明したのでpymysqlを導入。

#v_env下だとpymysqlがなかったので導入
pip install pymysql

するとURLは以下のようになる。
sqlalchemy.url = mysql + pymysql://root:(password)@example-rds-mysql-server.fmi3ou2hr9.us-east-2.rds.amazonaws.com/exampledb
これでうまくいった。
もう一度やると、env.pyで使っているmodelモジュールがないとのこと。パスが通ってなかったのでenv.pyを修正。

env.py
#target_metadata = Noneとなっているところを以下に修正
### modelsをインポートするためにパスを追加 ###
import os
import sys
root_dir = os.getcwd()
sys.path.insert(0, root_dir)
### metadata を設定 ### 
import models
target_metadata = models.Base.metadata

うまくいくか…

alembic upgrade head
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> e76a42708e85, Init tables

ようやくRDSにテーブルを作ることができた!migrations/versionsにあるmigrationスクリプトも自動生成されててalembicすごい。

まとめ

やったこととしては、
①alembicの導入、pymysqlの導入
②alembic initでフォルダ作成
③alembic.iniでDBのパスとscript_locationを修正
④env.pyでmodelsモジュールをインポート
⑤migrationファイルをautogenerateして、upgrade head
になります。

長くなってしまったので続きは別記事で。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.