前回の続き↓
[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
sql_alchemy.url=DBへのパス
#パスの書き方は後述
今回はモデルを別ファイルで定義することにしたので、models.pyをmigrationsディレクトリと同じ階層に作る。
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をインポートする。
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
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を修正。
#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
になります。
長くなってしまったので続きは別記事で。