Flask でよく使う雑多なテクニック

お久しぶりです。

以前に[ウェブアプリケーションフレームワーク Flask を使ってみる](https://qiita.com/ynakayama/items/2cc0b1d3cf1a2da612e4)という記事を書きましたが、その後 Flask を使って色々書いたのでよく使うテクニックを雑多に記述します。

## はじめに
### なぜ Python か

Python には [pandas を初め](https://qiita.com/ynakayama/items/7917f0f5eb556862642c)として素晴らしいデータ分析用のライブラリが揃っています。一般的なプログラミング言語としてウェブアプリケーションを記述でき、なおかつデータ分析も同じ言語・アプリケーション内で完結してしまえば、一石二鳥です。どう考えても便利ですね。

## Flask あるあるテクニック 

ここでは [Flask](http://flask.pocoo.org/)+[Jinja2](http://jinja.pocoo.org/) 前提で書いていきます。

### 基本的な画面の表示

はい。

```python
from flask import Flask, render_template

@app.route('/', methods=['GET'])
def Login():
    init_session()
    session['title'] = "ログイン"
    return render_template('login.html')
```

### ログイン処理
```python
@app.route('/dashboard', methods=['POST', 'GET'])
def Dashboard():
    if request.method == 'POST':
        if auth(request.form['id'], request.form['password']):
            session['alert_level'] = "success"
            session['alert_message'] = "ID: " + session['uid'] + " でログインに成功しました"

def auth(id, password):
    if isalnum_(id) and isalnum_(password):
        user = select_by_users(sql) # 適当、本当は SQLAlchemy とか使う
        if not user.empty:
            digest = get_hexdigest(password + user.salt)
            if user.password_hash == digest and user.active == "1":
                session['role'] = user.role # セッション情報に権限を格納
                return True
    return False
```

### パスワード更新
```python
    digest = get_hexdigest(new + static + salt)
    sql = "update users set password_salt = '%s', password_hash = '%s' where id = '%s';" % (salt, digest, session.get('id'))
    if exec_sql(sql):
        session['alert_level'] = "success"
        session['alert_message'] = "パスワードが変更されました。"
```

### JSON API

以前に [Ruby で書いた](https://qiita.com/ynakayama/items/b1eb6a9a39bf650dd517)のと同じ処理の Python 版。

```python
from flask import Flask jsonify
app.config['JSON_AS_ASCII'] = False # 日本語文字化け対策

@app.route('/api/balance_transition/show', methods=['GET'])
def Balance_Transition():
    if avail('Dashboard') is False:
        return redirect(url_for('Auth_Failure'))
    labels = []
    data = []
    maxdata = ""
    balance_transitions = select_by_blanace_transitions(sql) # 適当

    for i,balance_transition in balance_transitions.iterrows():
        labels.append(balance_transition['month'])
        data.append(balance_transition['balance'])
    if len(data) > 0:
        maxdata = max(data)

    json_data = {
      'type': 'bar',
      'data': {
        'labels': labels,
        'datasets': [{
          'label': "残高",
          'backgroundColor': "rgba(2,117,216,1)",
          'borderColor': "rgba(2,117,216,1)",
          'data': data,
        }],
      },
      'options': {
        'scales': {
          'xAxes': [{
            'time': {
              'unit': 'month'
            },
            'gridLines': {
              'display': False
            },
            'ticks': {
              'maxTicksLimit': len(labels)
            }
          }],
          'yAxes': [{
            'ticks': {
              'min': 0,
              'max': maxdata,
              'maxTicksLimit': len(data)
            },
            'gridLines': {
              'display': True
            }
          }],
        },
        'legend': {
          'display': False
        }
      }
    }
    return jsonify(json_data)
```

### static とか templates の名前を変える

```python
app = Flask(__name__, static_folder='static', static_url_path='')
```

### セッション情報をランダムなキーで暗号化

```python
from flask import Flask, session

app.secret_key = "".join([choice(string.ascii_letters + string.digits + '_' + '-' + '!' + '#' + '&')
                          for i in range(64)])
```

徒然なるままに書きましたが以上です。