はじめに
pythonからデータベースをいじる時に、クエリをベタ書きするんじゃなくてORMを利用することでコードがすっきりするのでサーバーサイドやデータサイエンスに興味ある人にはマストだと思います。
ORMとは?
オブジェクト関係マッピング(Object-Relational Mapping)の略称。
言語からSQLを操作する時に、SQLドライバを入れてクエリ書いて実行する(Ex. mysql-connecter)という方法がある。
でも、これだと上に書いたように処理が多い時に綺麗にコードが書きづらい!
ってことでそれを解消するのにORMが役にたつ!
簡単に言うとSQLを関数的に使うことができる。
今回使うpython用ORMは【dataset】
環境
OS:MacOS OSX10.11.6
言語:python3.5.2
ORM:dataset0.8.0
DBMS:mysql
導入
これだけ。
sudo pip install dataset
だけど、MySQLdbがimportできない!っていうエラー出ることがあります。
その時は、以下のパッケージをインストールしてください。
pip install mysqlclient
これで、python3でMySQLdbをimportすることができてdatasetをインストールすることができると思います。
実践
SQL文と対応させながら基本的な使い方を説明します。
今回は練習用に研究室のデータベースサーバー【db01】を使います。
データベースは【TrainLine】で、小田急線の駅名が入っています。
接続
まず、DBと接続します。
import dataset
# 対象のDBを指定
DBMS = 'mysql'
USER = 'root'
PASS = '~'
HOST = '対象DBのIPアドレス'
DB = 'TrainLine'
TABLE='Station_Name'
# 文字コードで悩む人へ
CHARSET = 'utf8'
db = dataset.connect('{0}://{1}:{2}@{3}/{4}?charset={5}'.format(DBMS, USER, PASS, HOST, DB, CHARSET))
table = db[TABLE]
DBMS:MySQL,PostgreSQL,sqliteとか対象のDBMSを指定
USER:ログインしたいユーザー名を指定
PASS:パスワードが必要なユーザーの時は指定
HOST:サーバーのアドレスを指定(IPアドレスでも可)
DB:使用するDB名を指定
TABLE:使用するテーブル名を指定
これで実行してエラーが出なければ接続完了。
次に実際にSQLを実行していきます。
SELECT文(複数)
複数レコードをselectする時はfind()を使います。
# SQL:SELECT * FROM Station_Name
results = table.find()
for record in results:
# OrderDict型で1レコードずつ出力される
print(record)
# カラムを指定することで特定の情報を引き出せる
print(record['Station_ID'])
print(record['Name'])
selectされたデータはOrderDict型で返ってきます。
ちなみにOrderDict型は、順番を保持した辞書型のデータです。
複数のレコードをselectしているため、for文を使うことで1レコードずついじれます。
1レコードに対して、カラムを指定することで情報を抽出できます。
===SQL:SELECT * FROM Staion_Name===
OrderedDict([('Station_ID', 2500101), ('Name', '新宿')])
2500101
新宿
OrderedDict([('Station_ID', 2500102), ('Name', '南新宿')])
2500102
南新宿
OrderedDict([('Station_ID', 2500103), ('Name', '参宮橋')])
2500103
参宮橋
OrderedDict([('Station_ID', 2500104), ('Name', '代々木八幡')])
2500104
代々木八幡
OrderedDict([('Station_ID', 2500105), ('Name', '代々木上原')])
2500105
代々木上原
・・・
WHERE句での指定SELECT
SQLで特定の情報を持つレコードをselectするのにWHERE句を使います。
このORMではfind関数の引数にカラムと値を指定することで実現できます。
## where句での指定
# SQL:SELECT * FROM Staion_Name WHERE Station_ID = 2500101
results = table.find(Station_ID=2500101)
for record in results:
print(record)
===SQL:SELECT * FROM Staion_Name WHERE Station_ID = 2500101===
OrderedDict([('Station_ID', 2500101), ('Name', '新宿')])
LIMITの指定も可能
複数レコードをselectする際にレコード数を制限することができる。
## _limit変数でselectの数を制限
# SQL:SELECT * FROM Station_Name limit 10
results = table.find(_limit = 10)
for record in results:
print(record)
===SQL:SELECT * FROM Staion_ID = 2500101===
OrderedDict([('Station_ID', 2500101), ('Name', '新宿')])
SELECT文(単一)
単一のレコードだけをselectする時はfind_one()を使うとfor文を使わないでデータをいじれる。
# SQL:SELECT * FROM Staion_ID = 2500101
print(table.find_one(Station_ID = 2500101))
===SQL:SELECT * FROM Staion_Name limit 10===
OrderedDict([('Station_ID', 2500101), ('Name', '新宿')])
OrderedDict([('Station_ID', 2500102), ('Name', '南新宿')])
OrderedDict([('Station_ID', 2500103), ('Name', '参宮橋')])
OrderedDict([('Station_ID', 2500104), ('Name', '代々木八幡')])
OrderedDict([('Station_ID', 2500105), ('Name', '代々木上原')])
OrderedDict([('Station_ID', 2500106), ('Name', '東北沢')])
OrderedDict([('Station_ID', 2500107), ('Name', '下北沢')])
OrderedDict([('Station_ID', 2500108), ('Name', '世田谷代田')])
OrderedDict([('Station_ID', 2500109), ('Name', '梅ヶ丘')])
OrderedDict([('Station_ID', 2500110), ('Name', '豪徳寺')])
INSERT文(単一)
SQLだと覚えにくいINSERT文もORMを使うと直感的に操作できます。
INSERTしたいレコードデータは、dict型で生成します。
# INSERT文:insert()
# SQL:INSERT INTO Staion_Name VALUES (2500200, '新大久保')
## insertしたいレコード
data = dict(Station_ID=2500200, Name='新大久保')
table.insert(data)
for record in table.find(Station_ID=2500200): print(record)
===SQL:INSERT INTO Staion_Name VALUES (2500200, '新大久保')===
OrderedDict([('Station_ID', 2500200), ('Name', '新大久保')])
OrderedDict([('Station_ID', 2500200), ('Name', '新大久保')])
INSERT文(複数)
複数のレコードをいっきにINSERTする方法が以下です。
## 複数のinsert
print("===複数insert===")
table.insert_many([dict(Station_ID=2500201, Name='西日暮里'), dict(Station_ID=2500202, Name='五反田')])
time.sleep(3)
for ID in [2500201, 2500202]:print(table.find_one(Station_ID=ID))
===複数insert===
OrderedDict([('Station_ID', 2500201), ('Name', '西日暮里')])
OrderedDict([('Station_ID', 2500202), ('Name', '五反田')])
UPDATE文
INSERT文同様にレコードデータを生成します。
ポイントは生成したレコードとデータベースにあるUPDATEしたいレコードの値が共通のカラム(下ので例では、Station_ID)をupdate関数の第2引数に指定することです。
# UPDATE文:update()
# SQL:UPDATE Staion_Name SET (Name = 渋谷) WHERE Station_ID = 2500201
## updateしたいレコード
data = dict(Station_ID=2500201, Name='渋谷')
## updateするためのカラムを指定(第2引数)
table.update(data, ['Station_ID'])
print(table.find_one(Station_ID=2500201))
===SQL:UPDATE Staion_Name SET Name = 渋谷 WHERE Station_ID = 2500201===
OrderedDict([('Station_ID', 2500201), ('Name', '渋谷')])
DELETE文
削除したいレコードがあるときは、delete()を実行する。
delete関数の第1引数にレコードのプライマリキーのカラムと値を指定して削除ができます。
# DELETE文:delete()
# SQL:DELETE FROM Station_Name WHERE Station_ID = 2500202
for ID in [2500200, 2500201, 2500202]: table.delete(Station_ID=ID)
for ID in [2500201, 2500202]:print(table.find_one(Station_ID=ID))
===SQL:DELETE FROM Station_Name WHERE Station_ID = 2500202===
None
None
COUNT文
カラムの値を指定することでその値を持つレコード数を数えることができます。
このORMではWHERE句の不等式での指定ができないため、レコードが存在するかどうかに使えそう。
# COUNT文:count()
# SQL:SELECT COUNT(*) FROM Station_Name WHERE Station_ID = 2500101
## WHERE句は等式でしか指定できないためレコードを確かめるのとかに使える
print(table.count(Station_ID = 2500101))
print(table.count(Station_ID = 2500301))
===SQL:SELECT COUNT(*) FROM Station_Name WHERE Station_ID = 2500101===
1
0
終わりに
これでpython用ORM【dataset】の説明終わります。
最低限の使い方はわかると思います。
他にも機能を使いたければ、直接gitをリファレンスするといいと思います。
ORMは知っておいて損はない知識・技術だと思うので、自分が使い慣れてる言語で1つは身につけておくと良いと思います。
読んでくれた方の参考になれば幸いです。