Python3でSQLSoupを使用して簡単にMySQLにアクセスする
2017/10/11
IT dockerpythonmysql

Python3系でMySQLへの参照、更新などができるようにしたときのメモ。

SQLAlchemyを使おうとしたが、DB定義に合わせてsetter/getterを用意する必要があるようだ。今回の要件から考えるとsetter/getterを用意するのは面倒くさい。

setter/getterを用意しないでDBを触るのであれば、railsのActiveRecordモジュールを使用すれば非常に簡単に実現できるのだが、どうしてもPython3系で実現する必要があった。

ちょっと調べてみたところSQLSoupというモジュールを使用することで、railsのActiveRecordまでではないが、比較的簡単に使用することができるようになった。

前提

ディレクトリ構成

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

コマンド実行手順

dockerの起動

1
2
3
cd docker
sh ./start.sh
cd ..

Pythonスクリプトの実行

1
sh ./run.sh

dockerの終了

1
2
3
cd docker
sh ./stop.sh
cd ..

stop.sh では、volumeの削除まではしていないので、mysqlのデータを破棄したいときには docker volume prune を実行する。

実際のソースコード

ソース概要

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)