Flaskクイックスタート

[Flask](http://flask.pocoo.org): python製のマイクロwebフレームワーク。

```bash:インストール
$ pip install flask
```

## 1. 基本構成

```python:app.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "hello world!"

if __name__ == "__main__":
    app.run()
```

実行

```bash
$ python app.py
```

実行：v0.11以降から flaskコマンドが使えるようになった。こちらを使うことが推奨。

```bash
$ export FLASK_APP=hello.py
$ export FLASK_DEBUG=1 # Debug Mode: コード変更時に自動でサーバー再起動
$ flask run [--host=0.0.0.0]
```

## 2. routeの書き方 

routing url に `<converter:variable_name>` を書くことで、
可変なurlに対応できる。

* converter: `string`, `int`, `float`, `path`, `any`, `uuid`

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

@app.route("/")
def hello():
    return render_template("index.html", key=value)

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        do_the_login()
    else:
        show_the_login_form()

if __name__ == "__main__":
    app.run()
```

```python:基本文法
- url_for('func_name', func_arg)
- @app.route('url', methods=['GET', 'POST'])
- render_template('index.html', key=value)
```

## 3. フォルダ構成

```
project
 |- app.py
 |- static/
 |- templates/
```

## 4. テンプレートファイルの書き方

jinja2 テンプレートが使える

```html+jinja
{{ variables }}
{{ variables | filter }}

{% logic %}
{% end logic %}
```

* filter: `safe` `capitalize` `lower` `upper` `title` `trim` `striptags`

```html+jinja
{{ url_for('static', filename='style.css') }}
```

## 5. context

context単位に対してに globalになる変数がある: `g` `request`

それらを unittestから扱いたいときは `test_request_context()` や `request_context()` を使う

```python
from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'
```

```python
from flask import request

with app.request_context(environ):
    assert request.method == 'POST'
```

## 6. アップロードされたファイルを保存する

* フォームは`enctype="multipart/form-data"`であること
* server側では `request.files` でアクセスできる
* 保存にはsave()メソッドが使える
* filenameプロパティーで clientのつけたファイル名が参照できるが、その際は、`werkzeug.utils.secure_filename()`等を使って、escapingすること。

```python
from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))
```

## 7. cookies

`request.cookies` `set_cookie` で cookieを扱える

```python
from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.
```

`make_response()`でresponseオブジェクトを作ってから、`set_cookie`する

```python
from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp
```

## 8. session

複数のrequestをまたいで globalに `session`がつかえる。pythonのdictだと思えばいい

```python
from flask import session

session['key'] = value
session.pop('key', None)
```

## 9. message flashing

python側では`flash()`をつかう

```python
from flask import flash

flash('message')
```

template側では`get_flashed_messages()`をつかう

```html+jinja
{% for message in get_flashed_messages() %}
  <div class="alert alert-warning">
    {{ message }}
  </div>
{% endfor %}
```

## 10. custom error page

`@app.errorhandler()` デコレータをつかう

```python
@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404
```

>
- http://flask.pocoo.org/docs/0.12/quickstart/