Flask と PostgreSQL Serverの接続覚書

# 環境作成

```bash
# 仮想環境の作成 + activate
$ python -m venv flask_to_postgresql
$ cd flask_to_postgresql/Scripts
$ ./activate

# 必要なパッケージ取得
$ python -m pip install --upgrade pip
$ pip install flask psycopg2-binary

# 環境確認
$ python --version
Python 3.9.13
$ pip list
Package            Version
------------------ -------
click              8.1.3
colorama           0.4.6
Flask              2.2.2
importlib-metadata 5.1.0
itsdangerous       2.1.2
Jinja2             3.1.2
MarkupSafe         2.1.1
pip                22.3.1
psycopg2-binary    2.9.5
setuptools         58.1.0
Werkzeug           2.2.2
zipp               3.11.0
```

``psycopg2-binary``はPostgreSQL Server接続用のパッケージ

# 参考サイト

- [FlaskからPostgreSQLを使用 via 高本技術士事務所](https://takamoto.biz/2022/01/flask%E3%81%8B%E3%82%89postgresql%E3%82%92%E4%BD%BF%E7%94%A8/)

# 軌跡

```python:flask_to_postgresql.py
from flask import Flask, render_template
import psycopg2
import psycopg2.extras

# Flask作成
app = Flask(__name__)

# ~/ にアクセスした際に表示するもの
@app.route('/')
def index():
    """_summary_
    従業員リストを表示
    """
    # PostgreSQL Serverとの接続を定義
    conn = psycopg2.connect(
        host='localhost',
        port=5432,
        database='test',
        user='testuser',
        password='testpassword',
    )

    # PostgreSQL Serverと接続を作成
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    # SQLを投入して情報取得
    cur.execute('select * from employee order by employee_id')
    # 結果を取得
    employee_list = cur.fetchall()
    # 接続終了
    conn.close()

    # データをhtmlに渡して表示
    return render_template(
        'flask_to_postgresql.html',
        title='Flask PostgreSQL',
        dataset=employee_list
    )

if __name__ == '__main__':
    # デバッグ出力を有効化
    app.debug = True
    # appを実行(ループバックアドレス + 80番ポート)
    app.run(host='127.0.0.1', port=80)
```
```html:templates/flask_to_postgresql.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>{{ title }}</title>
    </head>
    <body>
        <h2>社員一覧</h2>
        <ul>
            {% for line in dataset %}
            <li>{{ line.employee_id }} : {{ line.name }} : {{ line.abbreviation }}</li>
            {% endfor %}
        </ul>
    </body>
</html>
```

## 用語メモ
- [cursor とは - わわわ](https://wa3.i-3-i.info/word11582.html)
- [fetch とは - わわわ](https://wa3.i-3-i.info/word11583.html)

## 理解メモ

- ``psycopg2``の使い方の順序は以下
    1. DBの接続情報を作る(``conn = psycopg2.connect(～``)
    1. DBに接続する
    1. SQLを投入する
    1. 結果を取得する
    1. コネクションを閉じる
    1. 取得した結果を処理する
- ``psycopg2.extras.DictCursor``とは
    - [Python psycopg2 で dict形式で結果を取得する](https://qiita.com/itoufo/items/7306122497fd4f712bff)
    - [psycopg2 でよくやる操作まとめ](https://qiita.com/hoto17296/items/0ca1569d6fa54c7c4732)
        - オシャレな``with``を使った記載もある
        - 「実行結果を辞書形式で取得する」らしい
- テンプレートに渡す際の``dataset=employee_list``
    - ``dataset``は定型句ではなく何でも良い
    - ``.html``側は上記で指定された変数に対して操作できる

# 実行結果を辞書形式で取得 とは

```python:dict_what.py
import psycopg2
import psycopg2.extras

def main():
    """_summary_
    社員リストを表示
    """
    # PostgreSQL Serverとの接続を定義
    conn = psycopg2.connect(
        host='localhost',
        port=5432,
        database='srvrec',
        user='srvrec',
        password='vorpoc-2020-srvrec',
    )

    # PostgreSQL Serverと接続を作成
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    # SQLを投入して情報取得
    cur.execute('select * from employee order by employee_id')
    # 結果を取得
    row = cur.fetchall()
    print(row)

    # PostgreSQL Serverと接続を作成
    cur = conn.cursor()
    # SQLを投入して情報取得
    cur.execute('select * from employee order by employee_id')
    # 結果を取得
    bow = cur.fetchall()
    print(bow)
    # 接続終了
    conn.close()

if __name__ == '__main__':
    main()
```

``dict``指定の``row``と、無指定の``bow``の出力差を見てみる

```bash
$ python ./dict_what.py
[['100001', '北条 泰時'], ['100002', '北条 政子'], ['100003', '北条 時房'], ['100004', '三浦 義村']]
[('100001', '北条 泰時'), ('100002', '北条 政子'), ('100003', '北条 時房'), ('100004', '三浦 義村')]
```

- [Pythonの角括弧と丸括弧の違い、丸括弧を使う場合の注意点【()と[]、タプル型とリスト型】](https://noauto-nolife.com/post/python-brackets/)

あれ、てっきり``{}``で表示されるかと思ったけど違うのかな

```python:dict_what.py
import psycopg2
import psycopg2.extras

def main():
    """_summary_
    社員リストを表示
    """
    # PostgreSQL Serverとの接続を定義
    conn = psycopg2.connect(
        host='localhost',
        port=5432,
        database='srvrec',
        user='srvrec',
        password='vorpoc-2020-srvrec',
    )

    # PostgreSQL Serverと接続を作成
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    # SQLを投入して情報取得
    cur.execute('select * from employee order by employee_id')
    # 結果を取得
    row = cur.fetchone()
    print(row)
    print(type(row))

    # PostgreSQL Serverと接続を作成
    cur = conn.cursor()
    # SQLを投入して情報取得
    cur.execute('select * from employee order by employee_id')
    # 結果を取得
    bow = cur.fetchone()
    print(bow)
    print(type(bow))
    # 接続終了
    conn.close()

if __name__ == '__main__':
    main()
```

```bash
$ python .\dict_what.py
['100001', '北条 泰時']
<class 'psycopg2.extras.DictRow'>
('100001', '北条 泰時')
<class 'tuple'>
```

一応辞書型になってた。こっちのほうが使いやすそう