pythonでmysqlとalembicとsqlalchemyを使う

mysqlのコンテナを用意
このあたりを参考にさせて貰った
version: "3"
services:
mysql:
image: mysql:8.1.0
ports:
- 9002:3306 # portは適宜変更
environment:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: db
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- type: bind
source: mysql-data
target: /var/lib/mysql
consistency: delegated
db-cli:
image: mysql:8.1.0
command: mysql -hmysql -uuser -ppassword db
volumes:
mysql-data:
-
docker compose up -d
で起動 -
docker compose run db-cli
でmysqlのcliにログイン
関連ライブラリインストール
alembic
pymysql
mysqlclient
pip install -r requirements.txt
でインストール
sqlalchemyのmodelを定義し、それを元にmigrationファイル作成
基本は以下を参考に設定
動かなかった所1
自分の手元だとenv.pyに
from settings import Base
target_metadata = Base.metadata
を記述してもmodelが認識されなかったので、もう一つの方法として書かれている
target_metadata = [
User.metadata
]
こちらを使用したところちゃんと認識された。
動かなかった所2
settings.pyの中で
Engine = create_engine(
path,
encoding="utf-8",
echo=False
)
としているが、encodingを指定するとalembicコマンド実行時に以下のエラーが出た。
TypeError: Invalid argument(s) 'encoding' sent to create_engine(), using configuration MySQLDialect_pymysql/QueuePool/Engine. Please check that the keyword arguments are appropriate for this combination of components.
以下を見るとencodingという引数は無さそう。
代わりに接続文字列(path)の末尾にquery stringを付ける方法が使えそうなのでとりあえず指定しておく。(おそらくバージョンが新しくなって削除されたものと思われるが、これで同じ設定にできているのかは不明)
path = "mysql+pymysql://user:password@localhost:9002/db??charset=utf8"
このあたりはあまり理解してないので後でsqlalchemy側のドキュメントを見ておくべき。
マイグレーション実行
alembic upgrade head
を実行したら以下のエラー
sqlalchemy.exc.CompileError: (in table 'users', column 'name'): VARCHAR requires a length on dialect mysql
このあたりにある通り、mysqlの場合はString型のlengthを省略できないよという感じらしい
# before
sa.Column('name', sa.String(), nullable=True),
# after
sa.Column('name', sa.String(length=256), nullable=True),
無事に通るようになった
$ 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 -> 3b81cda1fd89, create tables
以下を実行し、usersテーブルが作られていることを確認
docker compose run db-cli
mysql> show tables;
+-----------------+
| Tables_in_db |
+-----------------+
| alembic_version |
| users |
+-----------------+
2 rows in set (0.00 sec)

strawberryを使ってGraphQLのAPIを作りたかった。
でもsqlalchemyで定義したmodelクラスに @strawberry.type
を付与すると ❌ Type User must define one or more fields.
みたいなエラーになってしまった。
自分で再定義しなくて良い方法はあるのかなと調べてみたら、一応以下のライブラリが使えた。
from strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper
import models # sqlalchemyのmodel定義
strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()
@strawberry_sqlalchemy_mapper.type(models.User) # @strawberry.type の代わりにこれを付与
class User:
# ここにfieldなどを自分で定義しなくて済む
pass
とても便利だけどスターの数とか見る限りはちゃんと運用していけるのか若干不安。
とはいえ個人開発用なので今回は採用してみようと思う。