はじめに
ホワイトデーにはアリをお返し🐜 nikkieです。
FastAPIで使うSQLModelの素振りです。
SQLAlchemyの知識も必要になってくるのですが、どちらも今はまだ初学者レベルですので、考え違いをしていたらやさしく教えてください!
目次
動作環境
dockerコンテナでPostgreSQLを立ち上げます。
macOSでRancher Desktopを使っています。
% docker --version
Docker version 27.5.0-rd, build 7a37716
% docker run --rm --name postgres \
-e POSTGRES_USER=developer \
-e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_DB=practice \
-p 5432:5432 -d postgres:15.10
DBに接続した後は、以前のスクリプトの内容でINSERTします(Hero 1人を登録!)。
SQLiteで動かしたスクリプトがこちらにあります。
各種バージョン
- Python 3.12.8
- sqlmodel 0.0.22
- SQLAlchemy 2.0.38
- psycopg2 2.9.10
SQLAlchemy[postgresql]というextra指定で入ります1
SQLModelドキュメントのやり方(Session)
sqlmodel.Sessionを使うやり方です。
sqlalchemy.orm.Sessionを加工したクラスですね2。
PostgreSQLへの接続まわりは
- DBの接続URLを組み立て
create_engine()- この実体は
sqlalchemy.engine.create_engine()です3。何も変えていません
- この実体は
- insertする際は
engineからSessionを作成
実行結果4
Before insert: name='Deadpond' secret_name='Dive Wilson' id=None age=None After add: name='Deadpond' secret_name='Dive Wilson' id=None age=None After commit: After commit (access id): 1 After id access: age=None secret_name='Dive Wilson' id=1 name='Deadpond' After session close: age=None secret_name='Dive Wilson' id=1 name='Deadpond'
SQLAlchemyのsessionmakerを試す
SQLModelのドキュメントから外に目を向けると、sessionmakerなるものの存在を知りました5。
+from sqlalchemy.orm import sessionmaker -from sqlmodel import Field, Session, SQLModel, create_engine +from sqlmodel import Field, SQLModel, create_engine # 省略 database_url = "postgresql://developer:mysecretpassword@127.0.0.1:5432/practice" engine = create_engine(database_url) +Session = sessionmaker(engine) if __name__ == "__main__": # 省略 + with Session(engine) as session: - with Session() as session:
全容はこちらでどうぞ
https://gist.github.com/ftnext/554c6365f1232f153ff517c89b911066
実行結果
Before insert: name='Deadpond' secret_name='Dive Wilson' id=None age=None After add: name='Deadpond' secret_name='Dive Wilson' id=None age=None After commit: After commit (access id): 2 After id access: secret_name='Dive Wilson' id=2 name='Deadpond' age=None After session close: secret_name='Dive Wilson' id=2 name='Deadpond' age=None
SQLAlchemyのドキュメントから
「Basics of Using a Session」の中の「Using a sessionmaker」
The purpose of
sessionmakeris to provide a factory forSessionobjects with a fixed configuration.
sessionmakerはSessionオブジェクトのファクトリを提供(※端折った訳)
sessionmaker()の返り値Session(ファクトリ)を呼び出すと、(SQLAlchemyの)Sessionインスタンスが返るわけですね。
sessionmakerのAPIドキュメント
https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.sessionmaker
__call__()がSessionインスタンスを返しています
終わりに
SQLModelからPostgreSQLのDBに同期接続するにあたり、2つの方法を見ました。
- SQLModelドキュメントの
Session(engine) - SQLAlchemyの
sessionmakerを使うやり方(sessionmaker(engine)())
SQLAlchemyのsessionmakerの返り値のファクトリは、ドキュメントでまだ読み切れていない箇所があります6。
引き続き読んでいきます
- https://github.com/sqlalchemy/sqlalchemy/blob/rel_2_0_38/setup.cfg#L63↩
-
exec()メソッドを生やしています https://github.com/fastapi/sqlmodel/blob/0.0.22/sqlmodel/orm/session.py#L27↩ - https://github.com/fastapi/sqlmodel/blob/0.0.22/sqlmodel/__init__.py#L4↩
- ロギングはこちらから (echo=TrueするとコンソールにSQLもprintも出るので、SQLをファイルにロギングしています)↩
-
きっかけはrhoboroさんのリポジトリです。 https://github.com/rhoboro/async-fastapi-sqlalchemy/blob/12683934b451c76af5eea7ee5bf4e6c8342ca165/app/db.py#L17 私には初見なので、まずは同期版の
sessionmakerから押さえることにしました↩ -
sessionmaker(engine).begin()というやり方もできるような...↩