2018年12月2日日曜日

flaskでhello worldからの続き①htmlファイルを表示する

hello worldからチュートリアルのミニブログまでが少し飛んでいる気がするので、勉強がてらまとめています。

hello.pyでreturn 'Hello World'を出したあとからスタートして、少しずつ変えて行きます。

最終的に作るサイト

『WEBページ上のフォームに数字を入力して送信すると、データベースに格納される』

FlaskでHTMLファイルを表示する

まず、index.htmlを表示するだけ、という簡単なサイトを作ります。ファイル構成はこうです。

simple
├── hello.py
├── instance
│   └── simple.sqlite
├── schema.sql
└── templates
    └── index.html

flaskでは、render_templateモジュールをインポートするとテンプレートを入れることができます。テンプレートとなるindex.htmlはhello.pyと同じ階層にtemplatesディレクトリを作ってその中に入れます。

hello.py
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route('/')
def hello():
    return render_template('index.html')
 index.html
<!doctype html>
<title>index.html test</title>
<body>
this is test
</body>

  $ export FLASK_APP=hello.py
  $ flask run

で127.0.0.1:5000にアクセスすると、index.htmlが表示されることが確認できます。



FlaskでSQLiteに接続する

データベースはSQLiteを使います。チュートリアルではinit_dbというコマンドを使っていますが、今回は直接作ります。

先にテキストスキーマでテーブルの型を作ります。テーブルの列名は、通し番号のid、タイムスタンプ、入力値です。

schema.sql
DROP TABLE IF EXISTS post;
CREATE TABLE post (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  value INTEGER NOT NULL
);
これを使ってinscanceディレクトリにsimple.sqliteというデータベースファイルを作ります。

$ sqlite3 instance/simple.sqlite < schema.sql



instanceのパス

instanceはdbファイルを入れるディレクトリです。

hello.pyの中では、

app = Flask(__name__, instance_relative_config=True)
とすると相対パス設定ができます。このときの app.instance_path のデフォルトがどこかというと
/home/user/anaconda3/var/hello-instance/
となっていました。

今回はシンプルにしたいので、simpleの直下にinstanceがあります。この設定は手動でできて、hello.pyの中で

相対パスにするとValueError: If an instance path is provided it must be absolute. A relative path was given instead. というエラーが出て、絶対パスにしなさいということです。

app = Flask(__name__, instance_path='/home/../../simple/instance')
とします。この部分は各自変える必要があります。


表示するindex.html

html画面を編集します。


<!doctype html>
<title>index.html test</title>
<body>
  <form method="post">
    <label for="value">Enter int</label>
    <input name="value" id="value" required>
    <input type="submit" value="Submit">
  </form>
</body>
hello.pyにdbアクセスの部分を追加します。チュートリアルからコードを流用しながら変えていきます。
import os
import sqlite3
from flask import Blueprint, Flask, current_app, g, render_template, request
app = Flask(__name__, instance_path='/home/../../simple/instance')
app.config.from_mapping(
    DATABASE=os.path.join(app.instance_path, 'simple.sqlite')
    )

def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row
    return g.db

def RepresentsInt(s):
    try:
        int(s)
        return True
    except ValueError:
        return False

@app.route('/', methods=('GET', 'POST'))
def hello():
    if request.method == 'POST':
        enter_value = request.form['value']
        if RepresentsInt(enter_value):
            db = get_db()
            db.execute(
                      'INSERT INTO post (value) VALUES (?)', (enter_value,)
                      )
            db.commit()
    return render_template('index.html')

get_db()関数: Flaskのgモジュールを使ってDBとアクセスします
RepresentsInt()関数:入力値が整数であればTrue、そうでなければFalseを返します

RepresentIntがTrueのときだけ入力されますが、エラーのときはデータベースには書き込まれません。

SQLの結果を確認する

書き込まれた内容と確認するには、simpleディレクトリ上で
$ sqlite3 instance/simple.sqlite
sqlite> select * from post;
とすればOKです。
---

TODO:
flash()でerrorを入れる
db.close()を消したの使う

0 件のコメント:

コメントを投稿