SQLAlchemyを用いたRDB操作の流れ(初学者)
初めに
初めまして。筆者はバックエンド初学者の大学生です。最近、API開発で初めてSQLAlchemyを使用し、学んだ知識をアウトプットして残したい、という思いで記事を書くことにしました。初めて触った時によく理解できていなかった内容を中心に書いているので、他の初学者の方の参考になったら嬉しいですが、初学者なりの解釈のため、鵜呑みにはしないように注意してください。(ChatGPTに聞きながら知識の整理をしていますが、内容の正確さは保証できません。)もし誤った理解があれば指摘してくださると大変助かります。
オブジェクト指向(Object-Oriented Programming: OOP)
まずはオブジェクト指向についてさらっとまとめます。
オブジェクト指向は、「プログラムをオブジェクトという部品の集合として設計、実装する」考え方です。部品化することで共通の処理を再利用することができ、開発を効率化したり、プログラムの構成を管理しやすくできるといったメリットがあります。
- オブジェクト:属性(データ)とメソッド(処理)をひとまとめにしたもの
- クラス:オブジェクトの設計図、雛形。属性やメソッドの定義をまとめ、そこから複数のインスタンスを生成する。
#クラス class Dog: def __init__(self,name): self.name = name #属性 def bark(self): print(f"{self.name}:woof") #メソッド #インスタンス生成 pochi=Dog("ポチ") pochi.bark() # -> "ポチ:woof"
ORMとは
オブジェクト指向言語のクラス・インスタンスをRDBのテーブル・レコードと対応づける仕組み。
メリット:
データベースをオブジェクトとして操作できるようになる。開発者はデータベース操作に直接SQL文を使用することなく、開発に使用している言語でRDBを操作することができる。
SQLAlchemyとは
PythonのORMライブラリ。PythonでAPI開発をする際にこれを用いることで、モジュール内にSQL文を含めることなくRDB操作が行えるためコードが読みやすくなる。
クエリ:
データベースに対してやりたいことを指定する命令のこと。通常、SQL(Structured Query Language)文で命令を書く。
SQLAlchemyのORMでのクエリ:
SQLAlchemyのORMライブラリではSQL文をpythonコードで組み立て、クエリをオブジェクトとして見立てる。
SQLAlchemyを用いたRDB操作の流れをざっと追う
ToDoアプリにおけるToDoテーブルを想定しています。
1. ORMを使うための土台準備
必要なライブラリをインポート
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
-
create_engine
: データベースへの接続情報(URL)をもとに、SQLAlchemy のエンジン(DB とのやり取りを管理するオブジェクト)を作成する関数。 -
declarative_base
: この後に定義するモデルクラスをまとめて管理・設定できるようにするための基底クラスを生成する関数- モデルクラス:ORMを使う際にテーブルの構造をPythonのクラスで表現したもの
- 基底クラス:オブジェクト指向プログラミングにおいて、他のクラスが共通の機能や属性を引き継ぐための親。すべての子クラスはこの親クラスを継承する
-
sessionmaker
: 引数にエンジンを渡してそのエンジンを使うSessionクラスを生成する関数。Session クラス:データベース操作(クエリの実行やトランザクション管理)を行う
モデルクラスの基底クラス用意
Base = declarative_base()
- 以降のモデル定義はこの Base を継承して書く。
エンジン準備
engine = create_engine("sqlite:///app.db")
セッション準備
Session = sessionmaker(bind=engine)
session = Session()
2. テーブルに対応するモデルクラスを定義
class Todos(Base):
__tablename__:"todos"
id=Column(Interger, primary_key=True)
title=Column(String)
status=Column(String)
3. テーブル生成
Base.metadata.create_all(engine)
- Baseに入っているすべてのテーブルが作成される
4. (テーブルへのデータ挿入後)クエリオブジェクトの作成
q = session.query(Todos).filter(Todos.owner_id == user_id)
-
session.query(Todos)
:SQL文におけるSELECT * FROM todos
に相当するクエリオブジェクトを生成 -
.filter()
:SQL文におけるWHERE {条件}
で絞りこむ - この時点ではクエリオブジェクトを作成しただけで何も実行されない
5. クエリを実行して結果を取得
クエリオブジェクトをDBに投げて結果を取得するメソッド
all_todos: list[Todos] = q.all()
first_todo: Todos | None = q.first()
count: int = q.count()
組み立てた「クエリオブジェクト」に対して以下のようなメソッド呼び出してはじめてSQLが発行され、データベースとやり取りが行われる
-
.all()
クエリの結果を すべて Python のリストとして返す。
返り値の型はlist[モデルクラス]
。 -
.first()
クエリ結果の最初の1件を返す。
取得されるレコードがなければNone
を返す。
返り値の型はモデルクラス。 -
.count()
クエリ結果の件数(行数)を整数で返す。
内部的にはSELECT COUNT(*) …
が発行される。
返り値の型は int。
終わりに
SQLAlchemyを用いてAPIを構築した時は、よくわからずに書いていたコードの流れがこの記事を書き終えることにはやっとはっきり見えてきました。今後も学びをアウトプットすることでコードの理解を深めていこうと思います。初学者のために理論だけじゃなくて感覚的に理解できるような記事を書けるようになることを目指していきたいと思います。ここまで読んでいただいてありがとうございました。
Discussion