メモ：PythonのFlaskでJSONを返す

[少し前に試した django](https://qiita.com/DiveMasakazu/items/ab68b2614c536b83e07f)は若干面倒だったので、学習コストの低そうなFlaskを見てみる。
Windows2012＋Python3

# インストール

```
pip install flask
```

flask2がインストールされた。

```
from flask import Flask
```
でインポートすれば使える。
ライセンスはBSD

# 単純な利用
まずは単純な利用。
index.htmlは適当に作成して、pythonから呼ぶようにする。

```python:flask_sample.py
from flask import Flask
app = Flask(__name__, static_folder='.', static_url_path='')

@app.route('/')
def index():
    return app.send_static_file('index.html')
if __name__ == "__main__":
    app.run(port=8000, debug=True)
```

localhost:8000に繋ぐとindex.htmlが閲覧可能。
とりあずWebサーバとして実行させるだけなら簡単。

# Jinja2
テンプレートエンジンが付いてくるので、これを利用する。
[ここ](https://qiita.com/zaburo/items/5091041a5afb2a7dffc8)とか見ながら確認。



まずはtemplatesフォルダを作り、その中にテンプレートのhtmlと、呼び出すhtmlを用意する。

適用レイアウト
blockのcontentの中に

```html:layout.html
<!doctype html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block content %}
<!-- メインコンテンツ -->
{% endblock %}
</body>
</html>
```

呼び出す方。
適用レイアウトと、レイアウトに送り込むコンテンツをセット

```html:flask.html
{% extends "layout.html" %}
{% block content %}
<h1>Hello Flask.</h1>
{{ name }}
{% endblock %}
```

pythonのソースコードを書き換えて、render_templateを使って表示する。
ここではURLから値を取得する方式にしてみた。

```python:flask_sample.py
from flask import Flask,render_template
app = Flask(__name__, static_folder='.', static_url_path='')

@app.route('/')
def index():
    return app.send_static_file('index.html')

@app.route('/hello/<name>')
def hello(name=None):
    return render_template('flask.html', title='flask test', name=name) 

app.run(port=8000, debug=True)
```

URLから取得してみたが、勿論GETやPOSTからも取得可能
flaskというかrequestの機能を利用するので、どちらもrequestをインポートした上で
GETなら

```python
@app.route('/get_request', methods=['GET'])
def index():
    name = request.args.get('name')
```

POSTなら

```python
@app.route('/post_request', methods=['POST'])
def index():
   if request.method == 'POST':
        name = request.form['name']
```

のような形。

# JSON
jsonifyをインポートして利用する。
普通にHTMLを返す代わりにjsonifyで返せばよい。

```javascript
return jsonify({
            'data':data
        })
```

jsonifyの日本語の文字化け対策は

``
`app.config['JSON_AS_ASCII'] = False
```

を入れる。

# Postgres
nodejsではPostgresと繋いでいたが、Pythonではやっていなかったのでとりあえず有名なpsycopg2を入れて検索して結果を返してみる。
psycopg2のライセンスはLGPLなので商用で取り扱う場合はやや注意が必要。

とりあえずPostgresに接続して、検索結果を返すメソッドを用意

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

def connect():
    con = psycopg2.connect("host=" + "localhost" +
                           " port=" + "5432" +
                           " dbname=" + "postgres" +
                           " user=" + "postgres" +
                           " password=" + "rU9PYNKh")

    return con

def select_execute(con, sql, param):
    with con.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
        cur.execute(sql,param)
        rows = cur.fetchall()
    dict_result = []
    for row in rows:
        dict_result.append(dict(row))
    return dict_result

if __name__ == '__main__':
    con = connect()
```

FlaskではアクセスされたURLを利用して、JSONを返すようにしてみる。

```python
from flask import Flask, render_template, jsonify
import postgres

app = Flask(__name__, static_folder='.', static_url_path='')
con = None
sel_query='SELECT id,name from test where id=%(id)s'

@app.route('/')
def index():
    return app.send_static_file('index.html')

@app.route('/hello/<id>')
def hello(id=None):
    rtn = postgres.select_execute(con,sel_query,{'id':(id,)})
    return jsonify(rtn)

if __name__ == '__main__':
    con = postgres.connect() # タイムアウトやコネクションプールは無視する
    app.run(port=8000, debug=True)
```

ブラウザからアクセスすると返ってきた。
（select_executeでDict型配列にしているため）

```json
[
  {
    "id": 2, 
    "name": "two"
  }
]
```
おわり