Python3でSQLSoupを使用して簡単にMySQLにアクセスする
2017/10/11
Python3系でMySQLへの参照、更新などができるようにしたときのメモ。
SQLAlchemyを使おうとしたが、DB定義に合わせてsetter/getterを用意する必要があるようだ。今回の要件から考えるとsetter/getterを用意するのは面倒くさい。
setter/getterを用意しないでDBを触るのであれば、railsのActiveRecordモジュールを使用すれば非常に簡単に実現できるのだが、どうしてもPython3系で実現する必要があった。
ちょっと調べてみたところSQLSoupというモジュールを使用することで、railsのActiveRecordまでではないが、比較的簡単に使用することができるようになった。
前提
- 今回の要件では、本記事のソースに記載されたツール以外にも色々と外部のツールをインストールする必要があった。このため、pythonベースのdockerコンテナではなく、AmazonLinuxのdockerコンテナを利用している。
- pythonのバージョンは自由に選択できるようにしておいた方が使い回しが効くので、pyenvを使用して特定のバージョンをインストールするようにした。
ディレクトリ構成
1
2
3
4
5
6
7
8
9
10
| run.py
run.sh
docker/
├── build
│ └── Dockerfile
├── db_init
│ └── db_init.sql
├── docker-compose.yml
├── start.sh
└── stop.sh
|
run.py
は、実行対象のPythonスクリプト。
run.sh
は、 run.py
をdockerホスト側から実行するためのスクリプト。
db_init/*
はmysqlコンテナ用のデータベース初期化ファイル。
start.sh
はdockerの起動ファイル。
stop.sh
はdockerの終了ファイル。
コマンド実行手順
dockerの起動
1
2
3
| cd docker
sh ./start.sh
cd ..
|
Pythonスクリプトの実行
dockerの終了
1
2
3
| cd docker
sh ./stop.sh
cd ..
|
stop.sh
では、volumeの削除まではしていないので、mysqlのデータを破棄したいときには docker volume prune
を実行する。
実際のソースコード
ソース概要
- MySQLは、docker-compose.ymlで立ち上げているが、Pythonスクリプトは毎回コンテナを起動している。
- PythonスクリプトからMySQLに接続したいので、
sample_network
という共通のネットワークを作成して(start.sh)、MySQLコンテナ(docker-compose.yml)とPythonコンテナ(run.sh)で利用するようにしている。
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| FROM amazonlinux:2017.09
RUN sed -ie "s/releasever=latest/releasever=2017.09/" /etc/yum.conf && \
yum -y update
RUN yum install -y git zip unzip zsh patch zlib-devel openssl-devel gcc gcc-c++ make bzip2 bzip2-devel readline-devel
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN echo 'export LANG=ja_JP.UTF-8' >> ~/.bashrc
RUN git clone git://github.com/pyenv/pyenv.git ~/.pyenv
RUN echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc && \
echo 'eval "$(pyenv init -)"' >> ~/.bashrc && \
source ~/.bashrc
RUN ~/.pyenv/bin/pyenv install 3.6.1 && \
~/.pyenv/bin/pyenv rehash && \
~/.pyenv/bin/pyenv global 3.6.1
RUN ~/.pyenv/shims/pip install PyMySQL sqlsoup
RUN mkdir -p /app
WORKDIR /app
|
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| version: '3'
services:
mysql:
container_name: db
image: mysql:5.6
ports:
- '3306:3306'
environment:
MYSQL_ROOT_PASSWORD: password
volumes:
- db_data:/var/lib/mysql
- ./db_init:/docker-entrypoint-initdb.d
networks:
- sample_network
volumes:
db_data:
networks:
sample_network:
external: true
|
start.sh
1
2
3
4
5
| #! /bin/sh
docker build -t python -f ./build/Dockerfile .
docker network create --driver bridge sample_network
docker-compose up -d
|
stop.sh
1
2
3
4
| #! /bin/sh
docker-compose down
docker network rm sample_network
|
run.sh
1
2
3
4
5
6
7
| #! /bin/sh
ENV_LANG="LANG=ja_JP.UTF-8"
PYTHON="/root/.pyenv/shims/python -B"
COMMAND="${PYTHON} run.py"
docker run --rm -e ${ENV_LANG} -v `pwd`:/app --net sample_network --link db:db -it python ${COMMAND}
|
run.py
sample_database
データベースの users
テーブルに name
, profile
というカラムが存在しているときの例を示す。
データベースのユーザー名とパスワードはdocker-compose.ymlの設定通り、 root
, passwd
としている。
SQLSoupの公式サイトが詳しい。
なお、 SQLSoup
は、内部的に SQLAlchemy
を使用しているらしい。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| import pymysql
import sqlsoup
url = 'mysql+pymysql://root:password@db:3306/sample_database?charset=utf8mb4'
db = sqlsoup.SQLSoup(url)
# INSERT
record = {}
record['name'] = 'hogefuga'
record['profile'] = 'profile1'
db.users.insert(**record)
db.commit()
# UPDATE
conditions = {}
conditions['name'] = 'hogefuga'
db.users.filter_by(**conditions).update({'profile': 'hoge hoge'})
# SELECT
user = db.users.filter_by(**conditions).first()
if user is not None:
print('existed')
# UPDATE
user.profile += ' updated!'
db.commit()
else:
print('not existed')
users = db.users.limit(10).all()
for user in users:
print(user.name)
print(user.profile)
|