たなしょのメモ

日々勉強していることをつらつらと

開発環境構築(vagrant、postgresql、pythonでアプリをつくる)その3

テンプレートhtmlがdbのカラムの値を出力しない

listでデータを保持していたため出力されなかった。
下記がlistでデータを保持したままrender_htmlにデータを渡していたソース。

 # -*- coding: utf-8 -*-
from flask import Flask, render_template

import psycopg2 
app = Flask(__name__) 

@app.route('/') 
def hello():
    users = 'USERNAME'
    db = 'DABATABASE'
    password = 'PASSWORD'
    conn = psycopg2.connect(" user=" + users + " dbname=" + db + " password=" + password)

    cur = conn.cursor()
    cur.execute('select * from menu;')
    results = cur.fetchall()

    cur.close()
    conn.close()

    return render_template('dnselect.html', menues=results)

if __name__ == "__main__":
    app.run(host='0.0.0.0')

テンプレートhtml

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>HTMLFILE reading</title>
    </head>
    <body>
        <h1>Flask tutorial</h1>
        {% for menu in menues %}
            <p>name:{{menu.name}}  price:{{menu.price}} yen</p>
        {% endfor %}
    </body>
</html>

これだとname:とpticeとyenしか出なかったのでprint文で元のファイルを少し弄ってデータの中身を確認することにした。

# -*- coding: utf-8 -*-
import psycopg2
def hello():
    users = 'USERNAME'
    db = 'DATABASE'
    password = 'PASSWORD'
    conn = psycopg2.connect(" user=" + users + " dbname=" + db + " password=" + password)

    cur = conn.cursor()
    cur.execute('select * from menu;')
    results = cur.fetchall()

    cur.close()
    conn.close()

    print(results)


if __name__ == "__main__":
    hello()

結果を見てみるとlistでデータを保持していた。

$ python test_list.py
[(1, '\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x93', 400, 400), (2, '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x932', 300, 300), (3, '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x933', 200, 200), (4, '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x934', 100, 100), (5, '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x935', 50, 50)]

これはどうするかと検索していたら同じことで悩んでいた人がその人のブログを参考にした。
https://qiita.com/itoufo/items/7306122497fd4f712bff

ブログのように書き換えたprintモジュールを作成して起動させてみた。

import psycopg2
import psycopg2.extras


def dcit_smp():
    users = 'USERNAME'
    db = 'DATABASE'
    password = 'PASSWORD'
    conn = psycopg2.connect(" user=" + users + " dbname=" + db + " password=" + password)

    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute('select * from menu;')
    results = cur.fetchall()
    dict_result = []
    for row in results:
        dict_result.append(dict(row))

    cur.close()
    conn.close()

    print(dict_result)

if __name__ == "__main__":
    dcit_smp()

辞書型に変形されていた。

[{'price': 400, 'calorie': 400, 'name': '\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x93', 'id': 1}, {'price': 300, 'calorie': 300, 'name': '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x932', 'id': 2}, {'price': 200, 'calorie': 200, 'name': '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x933', 'id': 3}, {'price': 100, 'calorie': 100, 'name': '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x934', 'id': 4}, {'price': 50, 'calorie': 50, 'name': '  \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\xe5\xbc\x81\xe5\xbd\x935', 'id': 5}]

あとはモジュールを作り変えていく。

# -*- coding: utf-8 -*-
from flask import Flask, render_template
import psycopg2
import psycopg2.extras

app = Flask(__name__)

@app.route('/')
def hello():
    users = 'USERNAME'
    db = 'DATABASE'
    password = 'PASSWORD'
    conn = psycopg2.connect(" user=" + users + " dbname=" + db + " password=" + password)

    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute('select * from menu;')
    results = cur.fetchall()

    dict_result = []
    for row in results:
        dict_result.append(dict(row))

    cur.close()
    conn.close()

    return render_template('dnselect.html', menues=dict_result)

if __name__ == "__main__":
    app.run(host='0.0.0.0')

これで起動してみたら無事動かなかった。
エラーがまた出てきてしまった。

ASCII対策

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)

上記なようなエラーが出てたので調査してみた。

検索したら割と簡単に出てきた。
https://qiita.com/jack-low/items/91bf9b5342965352cbeb

うまいことモジュールに盛り込んでみた。

# -*- coding: utf-8 -*-
from flask import Flask, render_template
import psycopg2
import psycopg2.extras
import sys, codecs

app = Flask(__name__)

reload(sys)
sys.setdefaultencoding('utf-8')

@app.route('/')
def hello():
    users = 'USERNAME'
    db = 'DATABASE'
    password = 'PASSWORD'
    conn = psycopg2.connect(" user=" + users + " dbname=" + db + " password=" + password)

    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute('select * from menu;')
    results = cur.fetchall()

    dict_result = []
    for row in results:
        dict_result.append(dict(row))

    cur.close()
    conn.close()

    return render_template('dnselect.html', menues=dict_result)

if __name__ == "__main__":
    app.run(host='0.0.0.0')

起動してみたところうまく日本語に変換されていて必要な値が取ることができた。