Pythonのメモ(その1)SQLAlchemy を使う

Python

Pythonでデータベース(MySQL)を扱うために、SQLAlchemyを使ってみました。その時の手順のメモです。

【前提】
・pythonバージョン3.8
・DBはMySQLを使用、データベース「test」を作成済み

インストール

以下のパッケージを(インストールされていなければ)あらかじめインストールしておきます。
※これらがないと次の mysqlclient がインストールできませんでした。

# dnf install python38-devel 
# dnf install mysql-devel

SQLAlchemyを利用するための python パッケージをインストールします。

$ pip install sqlalchemy
$ pip install mysqlclient

DB操作のための準備

DBへの接続設定

create_engine 関数を用いて、MySQL データベースへの接続設定を行います。create_engine の引数は以下の通り。

mysql://(MySQLへの接続ユーザー名):(そのパスワード)@localhost/(データベース名)

「Webサイト構築メモ」で例示したケースでは次のようになります。

from sqlalchemy import create_engine
engine = create_engine('mysql://namae:Password-SQL-namae1@localhost/test')

Baseクラスの作成

次に、データベーステーブルと関連付けるためのBaseクラスを作成します。

from sqlalchemy.orm import declarative_base
Base = declarative_base()

Userクラスの作成

Baseクラスを継承したクラスを作成して、テーブル名やカラム名を定義します。ここでは、テーブル名 user、カラム名 id, name. fullname とした Userクラスを作成します。

from sqlalchemy import Column, Integer, String
class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    fullname = Column(String(30))

Userクラスのテーブル属性は、次のようにして確認することができます。

User.__table__
# Table('users', MetaData(), Column('id', Integer(), table=<users>, primary_key=True, nullable=False), Column('name', String(length=30), table=<users>), Column('fullname', String(length=30), table=<users>), schema=None)

テーブルの作成

この時点でまだテーブルを作っていなかったときは、以下のコマンドを実行することで、テーブルが新規に作成されます。

Base.metadata.create_all(engine)

なお、既にテーブルが存在していた場合は、このコマンドを実行しても何も起こりません。

Userクラスの別の作成方法

一方、既にテーブル(’users’)が作成済みである場合には、次のようにしてテーブル属性を直接取得することもできます。(用途としては、「テーブルはphpMyAdminを使って作成したけど、列をたくさん作ったので、いまさらUserクラスで変数を一つづつ設定していくのは面倒臭いなぁ、、、」というような時でしょうか??)

from sqlalchemy import MetaData, Table
metadata = MetaData()
users_table = Table('users', metadata, autoload_with=engine)
users_table
# Table('users', MetaData(), Column('id', INTEGER(), table=<users>, primary_key=True, nullable=False), Column('name', VARCHAR(collation='utf8mb4_general_ci', length=30), table=<users>), Column('fullname', VARCHAR(collation='utf8mb4_general_ci', length=30), table=<users>), schema=None)

これを利用すれば、もっと簡単に(テーブル名やカラム名をあらわに記述することなく)同様のクラスを作成することができます。

class User2(Base):
    __table__ = users_table

User2クラスは、Userクラスと同じものになります。(以下、Userクラスを使うことにします。)

sessionの作成

次に、sessionを作成します。

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()

DBとやり取りするための準備は、以上で完了です。

なお、DBとのやり取りを行った後、終了するときは、セッションを閉じます。

session.close()

DBの操作

データベースの基本操作は、以下の通りです。

Insert

データの挿入は、session.add() で行います。確定するには、session.commit() が必要です。

user1 = User(id=1, name='ed', fullname='Ed_Jones')
session.add(user1)
session.commit()

session.add_all() で、複数データの挿入ができます。

user2 = User(id=2, name='wendy', fullname='Wendy_Williams')
user3 = User(id=3, name='mary', fullname='Mary_Contrary')
session.add_all([user2, user3])
session.commit()

Select

データの抽出は、session.query() で行います。

for row in session.query(User).all():
    print(row.id, row.name, row.fullname)
1 ed Ed_Jones
2 wendy Wendy_Williams
3 mary Mary_Contrary

この例では、Userクラス全体を抽出しますが、属性を指定して抽出することもできます。

for row in session.query(User.id, User.name, User.fullname).all():
    print(row.id, row.name, row.fullname)

(この例では、全ての属性を指定したので、結果は変わりません……)

抽出条件の設定は、filter() で行います。

userx = session.query(User).filter(User.id==2).first()
print(userx.id, userx.name, userx.fullname)
2 wendy Wendy_Williams

その他、filter() のカッコ内の条件設定方法として、
・nameにwを含む …………… User.name.like(%w%)
・idが1より大かつ3より小…… (User.id>1) & (User.id<3)
・idが2または4に等しい……… (User.id==2) | (User.id==4)
などなど。結果はいずれも上の結果と同じです。

Update

データの更新は、抽出したデータを直接操作して行います。確定するには、session.commit() が必要です。
id=2 を name='fred', fullname='Fred_Flintstone' に更新する場合は、上で抽出した userx を使って、

userx.name = 'fred'
userx.fullname = 'Fred_Flintstone'
session.commit()

のようにして、直接更新します。確認してみます。

for row in session.query(User).all():
    print(row.id, row.name, row.fullname)
1 ed Ed Jones
2 fred Fred_Flintstone
3 mary Mary_Contrary

なお、この抽出–>更新という流れは、次のように一つにまとめて実行することもできます。

session.query(User).filter(User.id==2).update({'name': 'fred', 'fullname': 'Fred_Flintstone'})

抽出した結果に update メソッドを適用します。抽出した結果が複数ある場合は、すべて一律に更新されます。update の引数には、更新したい項目の辞書型のリストを設定します。

Delete

データの削除は、抽出した後、delete() で行います。id が 1 より大きいものを削除する場合は、

n = session.query(User).filter(User.id>1).delete()
print(n)
2

削除されるデータ数が返り値となります。全てのデータを削除する場合は、

session.query(User).delete()

です。削除を確定するには session.commit() が必要です。確定しないときは、session.rollback() でロールバックします。(add,update でも同じです。)

まとめ

データベースを使うための準備をして、実際に操作するまでの手続きをまとめると、次のようになります。データベースの定義部分、モデル(Userクラス)の定義部分、メインの操作部分に分割して整理しました。

database.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

engine = create_engine('mysql://namae:Password-SQL-namae1@localhost/test')
Session = sessionmaker(bind=engine)
Base = declarative_base()

model.py

from sqlalchemy import Column, Integer, String
from database import Base
class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    fullname = Column(String(30))

main.py

from database import Session
from model import User

session = Session()

user1 = User(id=4, name='wendy', fullname='Wendy Williams')
user2 = User(id=5, name='jack', fullname='Jack Bean')
try:
    session.add(user1)
    session.add(user2)
    session.commit()
    print('--- success ---')
except:
    session.rollback()
    print('--- false ---')
finally:
    for row in session.query(User).all():
        print(row.id, row.name, row.fullname)
    session.close()

実行結果

--- success ---
1 ed Ed Jones
2 fred Fred_Flintstone
3 mary Mary_Contrary
4 wendy Wendy Williams
5 jack Jack Bean

参考

オブジェクトリレーショナルチュートリアル(1.x API)
SQLAlchemyを使ってPythonでORM ― SQLAlchemy ORMを知る
SQLAlchemy ORMの基本的な使い方



タイトルとURLをコピーしました