2. Flaskチュートリアル

Flask公式チュートリアルのFlaskrというブログアプリを作っていきます。

公式のチュートリアルではsqliteを直接使っていますが、 今回はSQLAlchemyを使っていきます。

Step 0

まずはディレクトリを作成します。

最終的なディレクトリとファイルは以下の様な構成となります。:

manage.py
requirements.txt
flaskr/
  |- __init__.py
  |- config.py
  |- views.py
  |- models.py
  |- static/
      |- style.css
  |- templates/
      |- layout.html
      |- show_entries.html

以下の様な感じで作成します。:

cd 先ほどhelloworldディレクトリを作成したディレクトリ
mkdir -p tutorial/flaskr/{static,templates}
cd tutorial
touch manage.py requirements.txt
touch flaskr/{__init__,views,models,config}.py
touch flaskr/static/style.css
touch flaskr/templates/{layout,show_entries}.html

requirements.txt

このブログアプリに必要なライブラリを記述します。

Flask
Flask-SQLAlchemy

ここに記述したライブラリは、:

pip install -r requirements.txt

を実行することでインストールすることができます。

記述したら実際に実行してみて下さい。

manage.py

flaskrを起動して実行するためのファイルです。

from flaskr import app
app.run(host='127.0.0.1', port=5000, debug=True)

flaskr/__init__.py

FlaskとプラグインのSQLAlchemyを生成します。

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object('flaskr.config')

db = SQLAlchemy(app)

import flaskr.views

app.config.from_object(‘flaskr.config’)はFlaskのconfigが 設定ファイルを読み込む処理で、他にも以下のような処理があります。

  • app.config.from_envvar: 環境変数から読み込む
  • app.config.from_object: pythonオブジェクトから読み込む
  • app.config.from_pyfile: pythonファイルから読み込む

flaskr/config.py

データベースの設定と、セッション情報を暗号化するためのキーを設定します。

SQLALCHEMY_DATABASE_URI = 'sqlite:///flaskr.db'
SECRET_KEY = 'secret key'

実際に運用する場合には、SECRET_KEYは必ず変更して下さい。

ちなみにFlaskのドキュメントには、以下のように生成すると良いと書かれています。:

>>> import os
>>> os.urandom(24)
'\xfd{H\flash: xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8

その他のファイルとディレクトリ

views.pyとmodels.pyは空のファイルで作成して下さい。あとから記述していきます。

staticとtemplatesも空のディレクトリで作成して下さい。あとからcssやhtmlを追加します。

Step 1

flaskrはブログなので、ブログの記事(データ)を格納する データベースを作ります。

flaskr/models.py

from flaskr import db

class Entry(db.Model):
    __tablename__ = 'entries'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.Text)
    text = db.Column(db.Text)

    def __repr__(self):
        return '<Entry id={id} title={title!r}>'.format(
                id=self.id, title=self.title)

def init():
    db.create_all()

作成したデータベース定義を読み込み、データベースファイルを作成します。:

$ python
>>> from flaskr.models import init
>>> init()

これで、flaskr/flaskr.dbが生成されてます。

動作を確認してみましょう。:

$ python
>>> from flaskr.models import Entry, db
>>> Entry.query.all()
[]
>>> entry = Entry(title='title', text='text')
>>> db.session.add(entry)
>>> db.session.commit()
>>> Entry.query.all()
[<Entry id=1 title=u'title'>]

>>> entry = Entry.query.get(1)
>>> entry
<Entry id=1 title=u'title'>
>>> entry.title = 'Hello world'
>>> db.session.add(entry)
>>> db.session.commit()
>>> Entry.query.all()
[<Entry id=1 title=u'Hello world'>]

>>> entry = Entry.query.filter(Entry.title == 'Hello world').first()
>>> entry
<Entry id=1 title=u'Hello world'>
>>> db.session.delete(entry)
>>> db.session.commit()
>>> Entry.query.all()
[]

Step 2

ブログの一覧と投稿画面を作ります。

投稿画面はログインしているときのみ操作できるようにします。

flaskr/views.py

from flask import request, redirect, url_for, render_template, flash
from flaskr import app, db
from flaskr.models import Entry

@app.route('/')
def show_entries():
    entries = Entry.query.order_by(Entry.id.desc()).all()
    return render_template('show_entries.html', entries=entries)

@app.route('/add', methods=['POST'])
def add_entry():
    entry = Entry(
            title=request.form['title'],
            text=request.form['text']
            )
    db.session.add(entry)
    db.session.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))

request:HTTPリクエストオブジェクト methodやフォームデータにアクセスできる
render_template:
 指定したHTMLテンプレートを使ってレスポンスを返す。
redirect:指定したURLにリダイレクトするレスポンスを返す。
url_for:指定したエンドポイントに対するURLを返す。
abort:指定したHTTPステータスコードのエラーを返す。
flash:メッセージを通知するための仕組み

Step 3

htmlテンプレートとcssを作ります。

flaskr/template/layout.html

<!doctype html>
<title>Flaskr</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<div class=page>
  <h1>Flaskr</h1>
  {% for message in get_flashed_messages() %}
    <div class=flash>{{ message }}</div>
  {% endfor %}
  {% block body %}{% endblock %}
</div>

flaskr/templates/show_entries.html

{% extends "layout.html" %}
{% block body %}
  <form action="{{ url_for('add_entry') }}" method=post class=add-entry>
    <dl>
      <dt>Title:
      <dd><input type=text size=20 name=title>
      <dt>Text:
      <dd><textarea name=text rows=5 cols=20></textarea>
      <dd><input type=submit value=Share>
    </dl>
  </form>

  <ul class=entries>
  {% for entry in entries %}
    <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
  {% else %}
    <li><em>Unbelievable.  No entries here so far</em>
  {% endfor %}
  </ul>
{% endblock %}

flaskr/static/style.css

body            { font-family: sans-serif; background: #eee; }
a, h1, h2       { color: #377ba8; }
h1, h2          { font-family: 'Georgia', serif; margin: 0; }
h1              { border-bottom: 2px solid #eee; }
h2              { font-size: 1.2em; }

.page           { margin: 2em auto; width: 35em; border: 5px solid #ccc;
                  padding: 0.8em; background: white; }
.entries        { list-style: none; margin: 0; padding: 0; }
.entries li     { margin: 0.8em 1.2em; }
.entries li h2  { margin-left: -1em; }
.add-entry      { font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl   { font-weight: bold; }
.metanav        { text-align: right; font-size: 0.8em; padding: 0.3em;
                  margin-bottom: 1em; background: #fafafa; }
.flash          { background: #cee5F5; padding: 0.5em;
                  border: 1px solid #aacbe2; }
.error          { background: #f0d6d6; padding: 0.5em; }

動かしてみる

python manage.py

http://127.0.0.1:5000 をブラウザで開いて動作を確認してください。