ポーカー、プログラミング、もぐ

ポーカーとプログラミングともぐもぐについてのブログ。

Flask on Heroku(Python3.4.2) その4 データベースを使う

asiagohan.hatenablog.com
asiagohan.hatenablog.com
asiagohan.hatenablog.com

今回は、前回まででフォームに入力できるようになったToDoを、
データベースに登録できるようにします。

データベース管理システムは、今回はPostgreSQLを利用します。postgresapp.com
こちらをインストールしたら、bash

export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/9.4/bin

と打ち、PATHを通します。

その後、

createdb todo

bash上で打ち、データベースを作成します。

データベースの作成が完了したら、flaskアプリケーションのコードを変更します。
config.pyに

SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/todo'

と一行追加します。

__init__.pyを、

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

app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)

from flask_app import views, models

と編集します。
今回はSQLAlchemyをORMとして使用します。

次に、flask_appディレクトリ下にmodels.pyを作成します。

from flask_app import db

class Todo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, index=True)
    detail = db.Column(db.String(5000))
    timestamp = db.Column(db.DateTime)

    def __repr__(self):
        return '<Todo %r>' % (self.title)

ORMを利用することで、modelをこのように記述することができます。

views.pyを編集し、データベースを利用するように変更します。

import datetime
from flask import render_template, flash, redirect, url_for, request

from flask_app import app, db
from .forms import TodoForm
from .models import Todo

@app.route('/')
def hello_world():
    return "Hello World!"

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = TodoForm()
    if request.method == 'POST' and form.validate():
        title = form.title.data
        detail = form.detail.data
        timestamp = datetime.datetime.utcnow()
        todo = Todo(title=title, detail=detail, timestamp=timestamp)
        db.session.add(todo)
        db.session.commit()
        return redirect(url_for('register'))

    todo_list = Todo.query.order_by(Todo.timestamp.desc())
    return render_template('register.html',
                           form=form,
                           todo_list=todo_list)

register関数を変更し、フォームに入力されたデータをデータベースへ登録するようにしました。
また、その後、データベースに登録されているデータを取得し、レンダリングを行うようにしました。

これに合わせて、テンプレートも変更します。
templates/register.htmlを編集します。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>register</title>
</head>
<body>
<h2>REGISTER</h2>
  <form action="" method="post" name="register">
      {{ form.hidden_tag() }}
      <p>
          title:<br>
          {{ form.title() }}<br>
      </p>
      {% for error in form.title.errors %}
            <span style="color: red;">TITLEを入力してください。</span>
          {% endfor %}<br>

      <p>
          detail:<br>
          {{ form.detail() }}<br>
      </p>
      <p><input type="submit" value="投稿" class="btn btn-primary"></p>
  </form>

{% for todo in todo_list %}
    <h2>{{ todo.title }}</h2>
    {{ todo.detail }}<br>
    {{ todo.timestamp }}
    <hr>
{% endfor %}



</body>
</html>

渡されたデータベースのデータを表示するように変更しました。

コードの編集が終わったら、一度プロジェクトディレクトリの中で、次のコードを実行します。

python
from flask_app import db
db.create_all()

これでデータベースにテーブルが作成され、利用準備が整いました。

http://127.0.0.1:5000/register へアクセスすると、
f:id:asiagohan:20150718184649j:plain
フォームが表示されます。

フォームに値を入力し、送信すると、
f:id:asiagohan:20150810124033j:plain
送信した値がデータベースに保存され、表示されます。

今回のコードは、
asiagohan/flask_tutorial_todo · GitHub
こちらに公開されています。

SICPをやる記録 その2 1.1〜1.1.6

SICP計算機プログラムの構造と解釈 第二版
1.1〜1.1.6までの学習記録。

• 基本式 言語が関る最も単純なものを表す.
• 組合せ法 より単純なものから合成物を作る.
• 抽象化法 合成物に名をつけ, 単一のものとして扱う.

f:id:asiagohan:20150721175051p:plain

数を表現する式は 基本的な手続き(+や*など)を表現する式と組み合せて合成式とし, 数に対するそれらの手続きの作用を表現することが出来る. 例えば:

(+ 137 349)
486

f:id:asiagohan:20150721175000p:plain
これがSchemeの文法か

式の並びを かっこで囲んで 手続きの作用を表現する上のような式を組合せ (combinations)という. 並びの左端の要素を 演算子(operator), 他の要素を 被演算子(operands)という. 組合せの 値は演算子が指定する手続きを, 被演算子の値である 引数(arguments)に作用させて得る.

オペレーター、オペランド

define で名前をつける(変数)
(define hoge 5)
で、解釈系はhogeと5を対応付ける。

値と記号を対応づけ, 後にそれが取り出せるためには, 解釈系は名前とオブジェクトの対を見失わないための, 何か記憶を保持していることに他ならないことは明らかである. この記憶を 環境(environment)(より正確には, 後になって計算は多くの異る環境に関るということが分る故に 大域環境(global environment))という.

f:id:asiagohan:20150721175045p:plain
グローバル!

評価の規則は, 本質的に 再帰的(recursive)である; つまり, 手順の一部に規則自身を呼び起す必要がある.

ある組み合わせの評価を完了させるには、組み合わせの各要素の評価を行わなくてはいけない。
組み合わせの要素をノードとし、組み合わせをツリーとする。
各ツリーのルートをノードとし、組み合わせ全体を一つのツリーとして表現する。

上の評価規則が定義は扱わないことに注意して欲しい. 例えば, (define x 3) の評価はdefineを二つの引数(一方は記号xの値で, もう一方は3)に作用させるのではない. defineの目的はxを値に対応づけることでしかない. (つまり, (define x 3)は組合せではない.)

defineは特殊形式であって、組み合わせではない。すなわち評価をすべきものではない。

一様な形に書けるのに, ただ便利ということで, 別の形をとる表層構文をPeter Landinの作った用語で構文シュガー(syntactic sugar)という。

f:id:asiagohan:20150721175040p:plain
言語によってこのあたりの考え方は違うのでしょうねえ...Pythonは同じことをやるのにはひとつのコード、という考え方ですし

さらに強力な抽象化技法である 手続き定義(procedure definitions)を学ぼう. これにより, 合成演算に名前を対応づけ, 一体として指すことが出来る.

関数ということでよいのかな?
手続き=プロシージャ ということか。プロシージャってなんだか言いにくいから、こんどプロシージャって出てきたら脳内で変換しておこう

(define (⟨name⟩ ⟨formal parameters⟩) ⟨body⟩)

name が合成手続きの名前、formal parametersが引数、bodyが値を評価するための式。bodyの中ではformal parametersが使われているが、
実際の呼び出しの際にはこのformal parametersが実際の引数と差し替えられて評価される。

例えば引数を二倍にして返す合成手続きdoubleは、
(define (double x) (* x 2))
で定義できる。

また、この合成手続きを使った合成手続きを定義することもできる。
5x^2 + 3y^2
を返す合成手続きを作る時、
まず
(define (square x) (* x x))
を定義し、
さらに
(define (nijishiki x y)(+ (* (square x) 5) (* (square y) 3)))
を定義すれば、

(nijishiki 2 3)
47

と合成手続きを使った合成手続きが定義できる。合成手続きは、基本手続き(+や*など、もともと用意されている手続き)と同じように使える。

合成手続きを引数に作用させるには, 各仮パラメタを対応する引数で取り替え, 手続きの本体を評価する.

評価する、というのは、要素の各組み合わせを評価し、結果をまた組み合わせとして評価し...を評価する必要がないところまで繰り返すこと。

置換えの目的は, われわれが手続き作用を考える時の補助であって, 解釈系の実際の働きを述べるものではない. 解釈系は仮パラメタに値を置き換えて, 手続きの字面を操作しつつ手続き作用を評価するのではない. 実際には, 「置換え」は, 仮パラメタの局所環境を使って実現している.

解釈系は引数をformal parametersと置き換えた後、評価しているのではない。

解釈系が評価を行うにあたって、その順序には種類がある。
作用的順序の評価(applicative-order evaluation):手続きに与えられた引数をformat parametersに置き換え、部分の組み合わせから評価する
正規順序の評価 (normal-order evaluation):基本的演算子だけを持つ式が出てくるまで引数の置き換えは行わない

場合分けにはcond、またはifを使う。
条件は基本的に出てきた順で評価される。

問題1.1

10

→10

(+ 5 3 4)

→12

(- 9 1)

→8

(/ 6 2)

→3

(+ (* 2 4) (- 4 6))

→6

(define a 3)

→a

(define b (+ a 1))

→b

(+ a b (* a b))

→19

(= a b)

→#f

(if (and (> b a) (< b (* a b)))
    b
    a)

→4

(cond ((= a 4) 6)
      ((= b 4) (+ 6 7 a))
      (else 25))

→16

(+ 2 (if (> b a) b a))

→6

(* (cond ((> a b) a)
         ((< a b) b)
         (else -1))
   (+ a 1))

→16

問題1.2
次の式を前置記法に翻訳せよ.
http://sicp.iijlab.net/fulltext/x116.1.png

(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5))))) (* 3 (- 6 2) (- 2 7)))

問題1.3
三つの数を引数としてとり, 大きい二つの数の二乗の和を返す手続きを定義せよ.

(define (square x) (* x x))
(define (sum-of-two x y) (+ (square x) (square y)))
(define (sum-of-biggers x y z) 
  (cond ((and (< x y) (< x z)) (sum-of-two y z)) 
            ((and (< y x) (< y z)) (sum-of-two x z)) 
            (else (sum-of-two x y))
  )
)

問題1.4

• 数字列の値は, その表す数値とする.
• 基本演算子の値は, 対応する演算を実行する機械命令の列とする.
• それ以外の名前の値は, その環境で名前と対応づけられたオブジェクトとする.
が基本的な式の扱いである。
そのため、帰結部が基本演算子の場合であっても、解釈系は基本演算子そのものを返す。

(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))

この式は、b>0のとき(+ a b)をbodyとし、それ以外の時は(- a b)をbodyとした合成手続きを返す。

問題1.5

作用的順序の場合:
(test 0 (p))
ここで、testの本体を取り出す
(if (= x 0)
0
y))
次に、仮パラメタを引数で置き換える
(if (= 0 0)
0
(p)))
このとき、yの代わりに(p)を置き換えようとしている。
しかし、この(p)を評価したとき、pは自身を返すため、無限ループに陥る。

正規順序の場合:
(test 0 (p))
ここで、testの本体を取り出す
(if (= x 0)
0
y))
次に、仮パラメタを引数で置き換える。ただしこの時、まだ基本演算子を持つ式のみとなっていないので、引数の評価を行わない。
(if (= 0 0)
0
(p)))
if式の評価を行う。(= 0 0)が真なため、0が返される。

SICPをやる記録 その1 前準備

計算機プログラムの構造と解釈 第二版


をやる記録。



まずはSchemeの処理系を入れないといけない。

Gauche - A Scheme Implementation

を使うことにする。



Macではhomebrewで入れられるようなので、

brew install gauche

でインストール。

しかしそのあと

gosh

と打ってもcommand not foundとなったので、

brew link gauche

で通るようになった。

    • -

なお、今後このブログで利用する「寿司ゆき」の画像は、awayuki.net
すべてこちらからお借りしています。

Flask on Heroku(Python3.4.2) その3 入力フォームを作る

Flask on Heroku(Python3.4.2) その1 環境構築 - ポーカー、プログラミング、もぐ

Flask on Heroku(Python3.4.2) その2 Hello World - ポーカー、プログラミング、もぐ

今回は、indexページに入力フォームをつけます。

Flaskでフォームを利用する時、ライブラリを利用するとバリデーションやHTMLの生成など、
フォーム周りの処理が楽になります。
今回はWTFormsを、Flask-WTFを使って利用します。

1,設定ファイルの作成
WTFormsを利用するために必要な設定を保存する、設定ファイルを作成します。

projectnameディレクトリ下に、config.pyファイルを作成します。

WTF_CSRF_ENABLED = True
SECRET_KEY = 'hogehoge'

WTF_CSRF_ENABLEDは、CSRF対策を行うかどうかの設定です。
WTF_CSRF_ENABLEDをTrueとした場合、SECRET_KEYを設定する必要があります。
SECRET_KEYは、推測が難しい文字列を入力します。

また、この設定を読み込ませるため、__init__.pyファイルを変更します。

from flask import Flask
app = Flask(__name__)
app.config.from_object('config')

from flask_app import views

app.config.from_object('config') の一行を追加します。

2,Formクラスの作成
WTFormsを利用する場合、まずフォームに対応するクラスを作成しなければいけません。
flask_appディレクトリ下に、forms.pyファイルを作成します。

from flask.ext.wtf import Form
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired, Length

class TodoForm(Form):
    title = StringField('title', validators=[DataRequired()])
    detail = TextAreaField('detail', validators=[Length(min=0, max=5000)])

3,viewへの追加
views.pyファイルを編集します。

from flask import render_template, flash, redirect, url_for, request

from flask_app import app
from .forms import TodoForm

@app.route('/')
def hello_world():
    return "Hello World!"

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = TodoForm()
    if request.method == 'POST' and form.validate():
        title = form.title.data
        detail = form.detail.data
        flash('title:{title}, detail:{detail}'.format(title=title, detail=detail))
        return redirect(url_for('register'))

    return render_template('register.html',
                           form=form)

変更点は以下の通りです。
・from flask import render_template, flash, redirect, url_for, request
を追加します。

・from .forms import TodoForm
を追加します。

・routeデコレータを使って、/registerのURLとregister関数を紐付けます。
register関数の中では、以下の処理を行っています。
form = TodoForm() : 先ほど作成したTodoFormクラスのインスタンスを生成しています。
if request.method == 'POST' and form.validate(): :POSTメソッドが利用され、かつフォームが正しく入力された時。以下のブロックでは、
フォームが入力・送信された時の処理を記述しています。
title = form.title.data、detail = form.detail.data  : フォームの入力値を変数にセットしています。
flash('title:{title}, detail:{detail}'.format(title=title, detail=detail)) : メッセージを受け渡しするためのflashを使っています。
return redirect(url_for('register')) : /registerへリダイレクトさせています。

return render_template('register.html',form=form):render_template関数を使って、HTMLを生成し返しています。

4,テンプレートの生成
templatesディレクトリ下に、register.htmlファイルを作成します。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>register</title>
</head>
<body>
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

<h2>REGISTER</h2>
  <form action="" method="post" name="register">
      {{ form.hidden_tag() }}
      <p>
          title:<br>
          {{ form.title() }}<br>
      </p>
      {% for error in form.title.errors %}
            <span style="color: red;">TITLEを入力してください。</span>
          {% endfor %}<br>

      <p>
          detail:<br>
          {{ form.detail() }}<br>
      </p>
      <p><input type="submit" value="投稿"></p>
  </form>


</body>
</html>

ここまで編集が終わったら、
http://127.0.0.1:5000/register
へアクセスします。
f:id:asiagohan:20150718184649j:plain
上記のようなページが表示されます。

フォームに入力して「投稿」ボタンを押すと、
f:id:asiagohan:20150718184701j:plain
入力された値がページ上に表示されます。

Flask on Heroku(Python3.4.2) その2 Hello World

その1asiagohan.hatenablog.com

今回はHello Worldです。

1,ディレクトリの作成

下記のようにディレクトリを作成します。

projectname

=flask_app

==static

==templates

2,flask_appパッケージのinitファイルの作成

flask_appディレクトリ下に、__init__.pyファイルを作成します。

from flask import Flask
app = Flask(__name__)

from flask_app import views

ここでは、Flaskクラスをインポートし、そのインスタンスを作成しています。
そしてその後、1で作成したflask_appパッケージからviewsをインポートしています。
(viewsはルーティングの役割を行うもので、この後の手順で作成します)

3,viewsの作成

flask_appディレクトリ下に、views.pyファイルを作成します。

from flask_app import app

@app.route('/')
def hello_world():
    return "Hello World!"

routeデコレータを使い、URLと関数を紐付けています。

4,run.pyの作成

projectnameディレクトリ下に、run.pyファイルを作成します。

from flask_app import app

app.run(debug=False)

run関数で、ローカルサーバを起動します。

5,実行
run.pyを実行します。(その1で生成したvirtualenvを起動しておくことを忘れずに)
実行後、
http://127.0.0.1:5000/
へブラウザを使ってアクセスすると、Hello World!が表示されています。

大根ステーキ 作り方メモ

1,大根を厚めに切り、皮をむく。

2,だし汁で大根を煮る。(おでんのときと同じくらいの味付け)

3,火が通ったら、フライパンにサラダ油をひき、大根に焼き目がつくまで焼く。

4,バターを落とし、溶けたら醤油を入れる。バター醤油を大根にからめる。

5,お皿に大根を盛る。フライパンに残ったソースをかける。

 

 

Flask on Heroku(Python3.4.2) その1 環境構築

#newscomment

こちらのWebアプリを作成したときの手順について記していきます。

Mac OSを使っています)

 

1,環境構築

virtualenvを使います。

virtualenv+virtualenvwrapper で、Python3.4.2の実行環境を作成。

Virtualenv — virtualenv 13.1.0 documentation

 

この中に、pipを使って必要なライブラリをインストールしていきます。

インストールしたのは

flask

flask-login

flask-sqlalchemy

flask-wtf

sqlalchemy-migrate

psycopg2

gunicorn

rauth

requests

です。

 

次に、今回データベースとして使用するPostgreSQLをインストールします。

PostgreSQL: Downloads

こちらからダウンロードし、インストールしました。

またGUIツールとして、

PG Commander, a PostgreSQL client for Mac

をインストールしました。

 

以上で、環境構築は終了です。

次回は、FlaskでのHelloWorldを行います。