SQLAlchemy って何者?ざっくりイメージ
SQLAlchemy は、「Python からデータベースを触るための超定番ライブラリ」です。
一言でいうと、
SQL を直接書く代わりに、Python のクラスやオブジェクトで
テーブル定義・INSERT・SELECT・UPDATE・DELETE を表現できる仕組み
です。
「生 SQL も書けるし、ORM(オブジェクトリレーショナルマッパー)としても使える」のが特徴で、
小さなスクリプトから本格的な Web アプリまで、幅広く使われています。
ここでは、まず「ORM としての SQLAlchemy」を軸に、
テーブル定義 → 接続 → CRUD(作る・読む・更新・削除)
という流れで、初心者向けにかみ砕いていきます。
SQLAlchemy の全体像を先にざっくりつかむ
「生 SQL でやっていたこと」を Python のクラスに置き換える
例えば、users テーブルを SQL で作るとこうでした。
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
SQLSQLAlchemy では、これを Python のクラスで表現します。
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, nullable=False)
Pythonこのクラスは、「users テーブルの 1 行」を表すモデルです。
クラス定義の中で、カラムの型や制約(primary_key, unique, nullable など)も一緒に書きます。
ここが SQLAlchemy の一番大事なポイントです。
「テーブル定義を Python のクラスとして持つ」ことで、
Python のオブジェクトを作る → INSERT
オブジェクトを検索する → SELECT
オブジェクトの属性を書き換える → UPDATE
オブジェクトを削除する → DELETE
という流れを、Python 的な書き味で書けるようになります。
接続とテーブル作成の基本フロー
エンジン(Engine)を作る
まずは「どの DB にどう接続するか」を表す Engine を作ります。
ここでは SQLite を例にします(学習に最適)。
from sqlalchemy import create_engine
engine = create_engine("sqlite:///example.db", echo=True)
Pythonsqlite:///example.db は、「カレントディレクトリの example.db という SQLite ファイル」という意味です。echo=True にすると、実際に発行される SQL がコンソールに表示されるので、学習時はかなりおすすめです。
PostgreSQL なら、例えばこうなります。
engine = create_engine(
"postgresql+psycopg2://user:password@localhost:5432/mydb",
echo=True,
)
Python接続文字列を変えるだけで、同じ ORM コードを別の DB に向けて使えるのも SQLAlchemy の強みです。
Base.metadata.create_all でテーブルを作る
先ほど定義した User クラス(Base を継承したモデル)を使って、
実際に DB にテーブルを作ります。
Base.metadata.create_all(engine)
Pythonこれを実行すると、User クラスの定義に基づいて、
users テーブルが example.db の中に作られます。
ここで重要なのは、「テーブル定義の“真実”が Python のクラス側にある」ということです。
SQL を手で書かなくても、クラス定義からテーブルが生成されます。
セッション(Session)と CRUD の基本
Session は「トランザクション付きの DB 接続」の窓口
SQLAlchemy では、実際の DB 操作は Session 経由で行います。
Session は、「トランザクションを意識した DB 操作の窓口」と思ってください。
まずは Session を作る準備をします。
from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(bind=engine)
Python使うときは、こんな感じです。
session = SessionLocal()
# ここで DB 操作をする
session.close()
Python実務では with 文で扱うことも多いですが、
まずは「Session を作って、終わったら閉じる」という流れを押さえれば十分です。
INSERT(レコードを作る)
User を 1 人追加してみます。
session = SessionLocal()
new_user = User(name="Taro", email="taro@example.com")
session.add(new_user)
session.commit()
session.close()
Python流れを言葉で追うと、
User オブジェクトを作る(まだ DB には書かれていない)
session.add で「このオブジェクトを保存対象にする」とマーク
session.commit でトランザクションを確定 → INSERT が実行される
という感じです。
commit を忘れると、実際の DB には反映されないので注意です。
これは SQLite でも PostgreSQL でも同じです。
SELECT(レコードを読む)
今度は、保存したユーザーを読み出してみます。
session = SessionLocal()
user = session.query(User).filter_by(email="taro@example.com").first()
print(user.id, user.name, user.email)
session.close()
Pythonsession.query(User) が「User テーブルに対する SELECT」のスタートです。
そこに filter_by(email="...") で WHERE 条件を足し、first() で最初の 1 件を取っています。
ここで重要なのは、「戻り値は User オブジェクト」だということです。user.name のように、Python の属性アクセスで値を扱えます。
UPDATE(レコードを更新)
更新も、オブジェクトの属性を書き換えるだけです。
session = SessionLocal()
user = session.query(User).filter_by(email="taro@example.com").first()
user.name = "Taro Yamada" # 属性を書き換える
session.commit() # ここで UPDATE が発行される
session.close()
PythonSQL を直接書くなら、
UPDATE users SET name = 'Taro Yamada' WHERE email = 'taro@example.com';
Pythonですが、SQLAlchemy では「オブジェクトの属性を書き換えて commit」という形で表現できます。
DELETE(レコードを削除)
削除も同じく、オブジェクトを取ってから session.delete します。
session = SessionLocal()
user = session.query(User).filter_by(email="taro@example.com").first()
session.delete(user)
session.commit()
session.close()
Pythonこれで、該当ユーザーの行が DB から削除されます。
SQLAlchemy の「大事な考え方」を少し深掘りする
モデルクラス=テーブル、インスタンス=行
SQLAlchemy ORM を理解するうえで、一番大事な対応関係はこれです。
モデルクラス(User)
テーブル(users)
モデルのインスタンス(User(…))
テーブルの 1 行
この対応が腹落ちすると、
「オブジェクトを作る → 行が増える」
「オブジェクトを検索する → 行を SELECT する」
「オブジェクトを変更する → 行を UPDATE する」
「オブジェクトを削除する → 行を DELETE する」
という流れが自然に見えてきます。
Session は「変更を覚えておいて、commit でまとめて流す」
Session のもう一つ大事な役割は、「変更の追跡」です。
Session の中で、
User を新しく作る(add)
既存の User の属性を書き換える
User を delete する
といった操作をすると、Session はそれらを全部覚えておきます。
そして session.commit() したタイミングで、
INSERT
UPDATE
DELETE
をまとめて DB に流します。
この「一連の変更をまとめて確定する」という動きは、
トランザクション(ACID)の考え方と直結しています。
JOIN や複数テーブルも少しだけイメージしておく
リレーション(関係)をモデルに書ける
SQLAlchemy の ORM では、テーブル同士の関係もクラスに書けます。
例えば、User と Post(ブログ記事)の関係を考えます。
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
posts = relationship("Post", back_populates="author")
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True)
title = Column(String, nullable=False)
body = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey("users.id"))
author = relationship("User", back_populates="posts")
Pythonこれで、
User 1 人に対して複数の Post(1 対多)
Post 1 件は 1 人の User に属する
という関係を、Python のクラスレベルで表現できます。
使うときは、こんな感じです。
session = SessionLocal()
user = User(name="Taro")
post1 = Post(title="Hello", body="First post", author=user)
post2 = Post(title="Second", body="Another post", author=user)
session.add(user)
session.add_all([post1, post2])
session.commit()
# 取り出す
u = session.query(User).filter_by(name="Taro").first()
for p in u.posts:
print(p.title)
session.close()
Pythonここで JOIN の SQL を自分で書いていませんが、
裏ではちゃんと JOIN されたクエリが発行されています。
「リレーションをクラスに書いておくと、Python 的なオブジェクト操作で JOIN 相当のことができる」
という感覚を持っておくと良いです。
まとめ(SQLAlchemy は「SQL と Python の橋渡し役」)
SQLAlchemy の基本を初心者目線で整理すると、こうなります。
テーブル定義を Python のクラス(モデル)として書くことで、「テーブル=クラス」「行=インスタンス」という対応ができる。
Engine で「どの DB に接続するか」を決め、Base.metadata.create_all(engine) でモデル定義からテーブルを自動生成できる。
Session は「トランザクション付きの DB 操作の窓口」で、オブジェクトの追加・変更・削除を追跡し、commit でまとめて INSERT / UPDATE / DELETE を流す。
SELECT も session.query(Model).filter(...).first() のように書けて、戻り値は生の行ではなく「モデルのインスタンス」になる。
リレーション(1 対多など)もクラスに書けるので、JOIN を意識せずにオブジェクト同士の関係として扱える。
「まずは 1 テーブル(User)だけで CRUD を一通り書いてみる」
「次に User–Post の 1 対多を追加してみる」
この 2 ステップをやると、SQLAlchemy の感覚がかなり掴めます。
