#SQLAlchemyとは
SQLAlchemyとは,Pythonの中でよく利用されているORMの1つ.
ORMとは,Object Relational Mapperのことで,簡単に説明すると,テーブルとクラスを1対1に対応させて,そのクラスのメソッド経由でデータを取得したり,変更したりできるようにする存在.
##ORMの利点とは
###1. 異なるDBの違いを吸収してくれる
DBの種類によらず,同じソースコードで操作できるので,複数のDBを併用する場合や,DBを変更する場合にも,コードの書き換えの必要がない.
###2. SQLを書かなくてもよい
MySQLや,SQLite,PostgreSQLなどのDBを操作するにはSQLを使うが,SQLAlchemyを使うと,SQLを直接記述することなしに,DBを"Pythonic"に操作できる.
#SQLAlchemyの使い方
簡単な流れとしては,どのDBにどうやって接続するか,設定を行う.(その設定内容を保持したものがエンジンと呼ばれる)
その後,マッピングを行い,セッションを作成する.
そして,そのセッションを使ってDB操作を行う.
##1. DBエンジンを作成する
from sqlalchemy import create_engine
engine = create_engine("{dialect}+{driver}://{username}:{password}@{host}:{port}/{database}?charset={charset_type})
のように書き,エンジンのインスタンスを作成する.各要素の説明は以下の表のとおり.
要素 | 説明 |
---|---|
dialect | DBの種類を指定する.sqlite, mysql, postgresql, oracle, mssqlとか. |
driver | DBに接続するためのドライバーの指定をする.指定しなければ,"default" DBAPIになる. |
username | DBに接続することができるユーザ名を指定する. |
password | DBに接続するためのパスワードを指定する. |
host | ホスト名を指定する.localhostとかIPアドレスとか. |
port | ポート番号を指定する.指定しなければ,defaultのポート番号になるっぽい? |
database | 接続するデータベース名を指定する. |
charset_type | 文字コードを指定する.utf8とか. |
例えば,以下のような感じ.(driverとportとcharset_typeは指定していない.)
engine = create_engine("mysql://scott:tiger@localhost/foo")
##2. モデルクラスを作る(テーブル定義を書く)
まずは,モデルベースクラスを作る.
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
そして,このベースクラスを拡張すると,ORMで扱えるモデルクラスになる.
例えば,以下のようにクラスを書けばよい.
また,モデルクラスを定義するときに,メソッドを追加することも可能である.
from sqlalchemy.schema import Column
from sqlalchemy.types import Integer, String
class User(Base):
__tablename__ = "user" # テーブル名を指定
user_id = Column(Integer, primary_key=True)
first_name = Column(String(255))
last_name = Column(String(255))
age = Column(Integer)
def full_name(self): # フルネームを返すメソッド
return "{self.first_name} {self.last_name}"
上で定義したのは以下の表のようなテーブルをマッピングさせたクラス.
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
user_id | int(11) | NO | PRI | NULL | auto_increment |
first_name | varchar(255) | YES | NULL | ||
last_name | varchar(255) | YES | NULL | ||
age | int(11) | YES | NULL | ||
このテーブルをDBに作成するには, |
Base.metadata.create_all(engine)
これで,Baseを継承しているテーブル郡が一括して作成される.
詳しいテーブル定義の内容は,以下.
SQLAlchemyでのテーブル定義
###metadataとは
上のコードでmetadataという言葉が出てきたが,metadataとは,DBの様々な情報を保持しているオブジェクトのこと.
このmetadataを使うと,既存のDBからテーブル定義をもってきたりすることもできる.
##3. セッションを作成する
SQLAlchemyはセッションを介してクエリを実行する.
そもそも,セッションとは,コネクションを確立してから切断するまでの一連の単位のこと.(DBとPythonコードを結びつける紐のようなものというイメージ)
セッションを作るクラスをsessionmakerで作る.(使うエンジンが一定なら,このとき指定する)
from sqlalchemy.orm import sessionmaker
SessionClass = sessionmaker(engine) # セッションを作るクラスを作成
session = SessionClass()
詳しい扱い方は以下.
SQLAlchemyでのsessionの扱い方
##4. CRUD処理を行う
CRUDというのは,以下の機能をまとめた呼び方のこと.
・Create(新規作成)
・Read(読み取り)
・Update(更新)
・Destroy(削除)
セッションを閉じたり,明にcommit()しないとDBが更新されないので注意.
###INSERT
新規オブジェクトをsessionにadd()すると,INSERT対象になる.
user_a = User(first_name="first_a", last_name="last_a", age=20)
session.add(user_a)
session.commit()
user_id | first_name | last_name | age |
---|---|---|---|
1 | a | a | 20 |
###SELECT
テーブルからデータを取り出すには,queryを使う.
users = session.query(User).all() # userテーブルの全レコードをクラスが入った配列で返す
user = session.query(User).first() # userテーブルの最初のレコードをクラスで返す
詳しくは,参考文献.
###UPDATE
セッションから取り出したオブジェクトを変更すると,UPDATE対象になる.
user_a = session.query(User).get(1) # 上で追加したuser_id=1のレコード
user_a.age = 10
session.commit()
user_id | first_name | last_name | age |
---|---|---|---|
1 | a | a | 10 |
###DELETE
セッションから取り出したオブジェクトをdelete()すると,DELETE対象になる.
user_a = session.query(User).get(1)
session.delete(user_a)
session.commit()
もしくは,検索条件にマッチするものを消すこともできる.
session.query(User).filter(User.user_id=1).delete()
session.commit()
##5. 既存のテーブルを使う場合
3では,新規のテーブルをマッピングしたクラスを作成したが,既存のテーブルをマッピングしたクラスを作りたいときもあるはず.
手順としては,Baseクラスにmetadataを渡し,__tablename__を既存のテーブル名に合わせて,autoloadをTrueにすればよい.
Baseクラスにmetadataを渡す方法としては,Baseクラスを作るときにengineを渡す方法
Base = declarative_base(bind=engine)
や,Baseクラスを作るときにmetadataを渡す方法
from sqlalchemy.schema import MetaData
meta = MetaData(engine)
meta.reflect() # metadataを取得, meta=MetaData(engine, reflect=True)と同じ
Base = declarative_base(metadata=meta)
や,Baseクラスを作ったあとに付与する方法
Base = declarative_base()
Base.metadata.bind = engine
がある.
例えば,テーブル名がexisiting_userというテーブルが存在していたとすれば.
Base = declarative_base(bind=engine)
class Exisiting_user(Base): # クラス名は何でもok
__tablename__ = "exisiting_user"
__table_args__ = {"autoload": True}
とすればよい.
#参考文献
この記事は以下の情報を参考にして執筆しました.
・公式ドキュメント
・PlaySQLAlchemy: SQLAlchemy入門
・SQLAlchemyでデータベース定義を楽したい
・【PythonのORM】SQLAlchemyで基本的なSQLクエリまとめ
・sqlalchemyのautomapによる既存のDBからのmodelの生成について