techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

Using a database with Flask

Using a database with Flask

前回に引き続き Head First Python, 2nd Edition - O'Reilly Media の内容。

今度はDBを使用する。

ローカル環境でDBを使う

Mac に DB 環境を構築する。

MariaDB をインストール

書籍の中では MySQL 推しだったが、MariaDB でも互換あるから大丈夫よということなので MariaDB を使ってみる。

インストーラのダウンロードはこちらから。
Downloads | MariaDB

.pkg ファイルなのでダイアログの通り進んでいけばインストール完了。

Installing MariaDB Server PKG packages on macOS - MariaDB Knowledge Base にある通り、以下のコマンドでrootログインできる。

sudo /usr/local/mariadb/server/bin/mariadb

パスワードは Mac にログインする際のもの。

DB とテーブルの作成

MariaDB に root ログインした状態でまずはDBを作成する。

MariaDB [(none)]> create database vsearchlogDB; 

次に、作成したDBにアクセスできるIDとパスワードを作成する。
ユーザー名(vsearch)とパスワード(vsearchpasswd)をそれぞれ指定する。

MariaDB [(none)]> grant all on vsearchlogDB.* to 'vsearch' identified by 'vsearchpasswd';
MariaDB [(none)]> quit

作成したIDでログインし直す。

$ /usr/local/mariadb/server/bin/mariadb -u vsearch -p vsearchlogDB
Password:

テーブルを作成する。

MariaDB [vsearchlogDB]> create table log (
    -> id int auto_increment primary key,
    -> ts timestamp default current_timestamp,
    -> phrase varchar(128) not null,
    -> letters varchar(32) not null,
    -> ip varchar(16) not null,
    -> browser_string varchar(256) not null,
    -> results varchar(64) not null);
Query OK, 0 rows affected (0.21 sec)

テーブルの内容を確認する。

MariaDB [vsearchlogDB]> describe log;
+----------------+--------------+------+-----+---------------------+----------------+
| Field          | Type         | Null | Key | Default             | Extra          |
+----------------+--------------+------+-----+---------------------+----------------+
| id             | int(11)      | NO   | PRI | NULL                | auto_increment |
| ts             | timestamp    | NO   |     | current_timestamp() |                |
| phrase         | varchar(128) | NO   |     | NULL                |                |
| letters        | varchar(32)  | NO   |     | NULL                |                |
| ip             | varchar(16)  | NO   |     | NULL                |                |
| browser_string | varchar(256) | NO   |     | NULL                |                |
| results        | varchar(64)  | NO   |     | NULL                |                |
+----------------+--------------+------+-----+---------------------+----------------+
7 rows in set (0.02 sec)

できとるできとる。

Python から DB 操作

Install MySQL-Connector/Python

Python から MariaDB, MySQL を操作するために Database Driver をインストールする。

MySQL / Download Connector/Python

取得して解凍するとmysql-connector-python-[バージョン]ディレクトリができるのでここに移動。
仮想環境を activate した状態で以下を実行する。

$ python setup.py install
running install
Not Installing MySQL C Extension
running build
running build_py
creating build
creating build/lib
creating build/lib/mysql
copying lib/mysql/__init__.py -> build/lib/mysql
creating build/lib/mysql/connector
・
・
・

これでインストール完了。
仮想環境の依存パッケージを確認してみる。

$ pip freeze
apipkg==1.4
click==6.7
execnet==1.5.0
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
mysql-connector-python==2.1.7
pep8==1.7.1
py==1.5.2
pytest==3.2.5
pytest-cache==1.0
pytest-pep8==1.0.6
vsearch==1.0
Werkzeug==0.14.1

入ってる入ってる。

Python コードからのDB操作

実際に Python >>> prompt から DB 操作してみる。

$ python
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> dbconfig = { 'host': '127.0.0.1',
... 'user': 'vsearch',
... 'password': 'vsearchpasswd',
... 'database': 'vsearchlogDB', }
>>> import mysql.connector
>>> conn = mysql.connector.connect(**dbconfig)
>>> cursor = conn.cursor()
>>> _SQL = """show tables"""
>>> cursor.execute(_SQL)
>>> res = cursor.fetchall()
>>> res
[('log',)]

意図通り動作していることがわかる。
データの書き込みも試してみる。

>>> _SQL = """insert into log
... (phrase, letters, ip, browser_string, results)
... values
... (%s, %s, %s, %s, %s)"""
>>> cursor.execute(_SQL, ('hitch-hiker', 'xyz', '127.0.0.1', 'Safari', 'set()'))
>>> conn.commit()

commit を忘れないように。
書き込んだデータを確認してみる。

>>> _SQL = """select * from log"""
>>> cursor.execute(_SQL)
>>> for row in cursor.fetchall():
...     print(row)
... 
(1, datetime.datetime(2018, 2, 10, 8, 28, 14), 'hitch-hiker', 'xyz', '127.0.0.1', 'Safari', 'set()')

意図通り。
使い終わったら close する。

>>> cursor.close()
True
>>> conn.close()

PythonAnywhere で DB を使う

ここまでのセットアップでローカル環境ではDBが使えるようになった。
PythonAnywhere 上で公開しているアプリでもDBを使えるようにする。

DB のセットアップ

ローカル環境では MariaDB を選択したが、PythonAnywhere でサポートされているDBは以下の通り。

  • MySQL
  • SQLite
  • Postgrs(有料アカウントでのみサポート)

Kinds of databases | PythonAnywhere help

今回は MariaDB と互換性のある MySQL を使用する。

PythonAnywhere の Databases タブで MySQL を選択する。
まずパスワードの設定を求められる。DBへのアクセス用だ。

Create a database で Dbatabase name を入力すれば DB 作成まで完了。

  • ユーザー名は PythonAnywhere のユーザー名に固定される
  • DB ホストアドレスも PythonAnywhere 側で決められる
  • DB 名もこちらで指定したものに ユーザー名+$ のプレフィックスを付けられる

といったルールがある模様。
ローカル環境でのconfigと分ける必要があるのでこんな感じにしてみた。

Add surpport for using DB on PythonAnywhere. · kfurue/hfpython-flask@01001ea

Create Table

DB は作成できたのでテーブルを作成していく。
DB タブに作成済みDBが表示され、Start a console on: が表示されるのでクリックすれば、mysql> コンソールにログインできる。

必要なテーブルを作成する。

mysql> create table log (
    -> id int auto_increment primary key,
    -> ts timestamp default current_timestamp,
    -> phrase varchar(128) not null,
    -> letters varchar(32) not null,
    -> ip varchar(16) not null,
    -> browser_string varchar(256) not null,
    -> results varchar(64) not null);
Query OK, 0 rows affected (0.03 sec)
mysql> describe log;
+----------------+--------------+------+-----+-------------------+----------------+
| Field          | Type         | Null | Key | Default           | Extra          |
+----------------+--------------+------+-----+-------------------+----------------+
| id             | int(11)      | NO   | PRI | NULL              | auto_increment |
| ts             | timestamp    | YES  |     | CURRENT_TIMESTAMP |                |
| phrase         | varchar(128) | NO   |     | NULL              |                |
| letters        | varchar(32)  | NO   |     | NULL              |                |
| ip             | varchar(16)  | NO   |     | NULL              |                |
| browser_string | varchar(256) | NO   |     | NULL              |                |
| results        | varchar(64)  | NO   |     | NULL              |                |
+----------------+--------------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)

Install Database Driver

PythonAnywhere 上のコンソールを使用する。
Connector/Pythonをダウンロードして解凍する。

$ wget https://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-2.1.7.zip
$ unzip mysql-connector-python-2.1.7.zip 
Archive:  mysql-connector-python-2.1.7.zip
$ cd mysql-connector-python-2.1.7/

PythonAnywhere上の仮想環境にインストールする。

$ workon my-virtualenv

インストール前の依存パッケージ一覧は以下の通り。

(my-virtualenv) $ pip freeze
-f /usr/share/pip-wheels
click==6.7
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
vsearch==1.0
Werkzeug==0.14.1

ここに MySQL Connector/Python をインストールする。

(my-virtualenv) $ python setup.py install
(my-virtualenv) $ pip freeze
-f /usr/share/pip-wheels
click==6.7
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
mysql-connector-python==2.1.7
vsearch==1.0
Werkzeug==0.14.1

完了。

これで PythonAnywhere 上で公開しているアプリでも MySQL が使用できる。

その他

A beginner's guide to building a simple database-backed Flask website on PythonAnywhere - PythonAnyw
こんな記事もあったが、紹介されているのはSQLAlchemy。どっこい実装では MySQL Connector/Python を使用しているのでローカル環境と同じ方法でインストールした。

pip install -r requirements.txt すればお手軽に環境コピーできるのが利点だったはずなのになんかそれ以外の手順が増えてきてしまった。
この辺りのベストプラクティスもきっとあるんだろうな。