概要
SQLAlchemy を使う際にいろいろなコンポーネントが必要になります
多くのサンプルではそれぞれを 1 つファイルで扱っているようですが、あまりキレイな書き方ではないかなと個人的には思います
なので、各役割ごとにクラスを作成し管理するようにしてみました
提案的な記事なので参考程度に見ていただけると嬉しいです
環境
- macOS X 10.13.6
- Python 3.6.5
- SQLAlchemy 1.2.10
- MySQL Server 5.7.22
engine を管理するクラスの作成
DB サーバに接続する engine を管理します
SQLAlchemy の場合 engine は create_engine
で作成します
DB サーバに接続する必要があるので DB サーバのへの接続情報 (ユーザ名、パスワード、ホスト名、データベース名など) はこのクラスで管理します
- vim base_engine.py
from sqlalchemy import create_engine
class BaseEngine(object):
def __init__(self):
username = 'username'
password = 'password'
hostname = 'localhost'
dbname = 'db_server'
url = 'mysql+mysqldb://{}:{}@{}/{}?charset=utf8'.format(username, password, hostname, dbname)
self.engine = create_engine(url, echo=True)
DB サーバに接続するための情報はサンプルなので決めうちにしていますが環境変数や設定ファイルから持ってくるようにしても良いと思います
キーワード引数で受け取れるようにしても良いと思います
Session を管理するクラスも追加する
Session は DB への CRUD 操作するために必須のオブジェクトになります
Session は engine を元に生成する必要があるため先ほど作成した BaseEngine クラスを継承します
今回は先ほど作成したファイル (base_engine.py) で管理します (特に理由はないので分けても OK です)
ただし、クラスは Session を管理するためのクラスを作成します
- vim base_engine.py
from sqlalchemy.orm import sessionmaker
class BaseSession(BaseEngine):
def __init__(self):
super().__init__()
Session = sessionmaker(bind=self.engine)
self.session = Session()
実際にアプリケーションから CRUD 操作をしたい場合はこのクラスを使います
使い方は後ほど紹介します
モデルを管理するクラスを作成
テーブルの構成を管理するクラスです
SQLAlchemy で言うところの Base を継承して作成するクラスになります
Column などを使ってテーブルのスキーマを定義します
- vim 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(20))
age = Column(Integer)
このクラスで肝になるのは Base
です
この Base クラスは DB に対してテーブルを作成する場合にも使います
いろいろなところで Base を declarative_base
するのは気持ち悪いので Base はここだけで扱うようにします
モデルクラスを元にマイグレートするクラスを作成する
作成したスキーマ情報を元に DB サーバに対してテーブルを作成したいと思います
DB サーバに対してテーブルを作成する場合には Base と engine が主に必要になります
それらは専用で管理しているクラスとしてすでに作成済みなのでそれらを import して使います
from base import BaseEngine
from models import User, Base
class Migration(object):
def __init__(self):
self.e = BaseEngine().engine
def users(self):
Base.metadata.create_all(self.e)
if __name__ == '__main__':
Migration().users()
- pipenv run python3 migrate.py
エンジンを作成して、そのエンジンを元に create_all
をコールするだけです
これで BaseEngine で指定したデータベース配下にテーブルを作成することができます
基本的にマイグレートするためのクラスは一度しか実行しない想定です
(SQLAlchemy の場合、すでにテーブルが存在する場合は何もしないので何度実行しても問題はないです)
CRUD してみる
作成したクラスを元に実際に SELECT 文を発行するクラスを作成してみます
必要になるのは Session を管理しているクラスと操作したいテーブルを管理しているモデルのクラスになります
- vim crud.py
from base import BaseSession
from models import User
class Users(BaseSession):
def __init__(self):
super().__init__()
def select(self):
for i in self.session.query(User).order_by(User.id):
print(i.name)
if __name__ == '__main__':
cli = Users()
cli.select()
サンプルはただ print しているだけです
このメソッドの返り値を User の配列などにしてもいいかなと思います
今回の構成の場合、こんな感じで CRUD したいテーブルごとにクラスを作成できるので、コードの管理がわかりやすくなるかなと思っています
必要に応じて更に CRUD 用のベースクラスなども作成できるかなと思います
最後に
SQLAlchemy を使う場合にどのようなモジュール、クラスの構成にしたほうが良いか考えてみました
もしかしたら探せばベストプラクティスが出てくるかもしれません
今回紹介したのは最低限の役割のみになります
トランザクション処理や Alter 処理、外部キー制約が絡んでくる場合にはもう少し考慮することが増えますが基本的には今回の構成を応用するだけかなと思っています
SQLAlchemy を使う人の参考になれば幸いです
0 件のコメント:
コメントを投稿