質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.50%

【Jinja2】python+flaskを使った開発。コンソール上では表示されるデータが、HTML上で表示できない。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 478

score 36

<後記、2021年5月6日> 
全体像として、何をやりたかったを、Githubに記載しました。
宜しかったら、眺めてください。改めて、皆さま、ありがとうございました。
https://github.com/kazu0116/web_application

=====================

HTMLと言うか、Jinja2の書き方の問題と言う気がするのですが、どうしても分かりません。
教えてください。

<背景>
Python Flaskを使用して、DB(mysql)サーバから、データを引っ張ってきて、HTMLに表示すると言う、下記の様なシステムを開発しております。

1)ユーザーは、HTML(index.html)上で、旅行したい国のチェックボックスにチェックを入れて(複数選択も可)、送信ボタンをクリックする。
![イメージ説明

2)選択された国の旅行情報を、DBから引っ張ってきて、コンソール上に表示すると共に、HTML(index1.html)に表示する。

<説明>
試行錯誤した結果、pythonの方は、下記の様なコードにたどり着きました。

from flask import Flask, render_template,request
import pymysql
app = Flask(__name__)

@app.route('/', methods=['GET'])
def get():
    return render_template('index.html', \
        title = 'Form Sample(get)', \
        message = 'Where do you want to go?')


def getConnection():
    return pymysql.connect(
        host='localhost',
        db='first_db',
        user='root',
        password='password',
        charset='utf8',
        cursorclass=pymysql.cursors.DictCursor
    )


@app.route('/', methods=['POST'])
def select_sql():
    connection = getConnection()
    message = "test"
    names = request.form.getlist('checkbox')

    for name in names:

        cursor = connection.cursor()
        sql = "select Country, Agency, email from tb3 where Country=%s";
        cursor.execute(sql, (name,))

        list1s = cursor.fetchall()  #TakaiYさんのコメントを受け、誤字修正
                 print(list1) #コンソール上での動作確認用

    cursor.close()  
    connection.close() 

    return render_template( 'index1.html', list1s = list1s) 

if __name__ == '__main__':
    app.run()

コンソール上への表示は、1つの国を選択した場合も、複数の国を選択した場合も、期待した通りのデータを返してきます。(ここまでは、OK。下記は、3か国を選択した場合のコンソール表示。)

<コンソール上では表示される>
[{'Country': 'Australia', 'Agency': 'DEF Travel', 'email': '456@yahoo.com'}]
[{'Country': 'England', 'Agency': 'GHI Travel', 'email': '789@hotmail.com'}]
[{'Country': 'France', 'Agency': 'JFK Travel', 'email': '1111@yahoo.co.jp'}]

<質問>
上記の様に、コンソール上には、問題なく表示されておりますが、HTML上で表示が上手くいきません。
(複数項目を選択した場合、最後にチェックした国(上記の例では、フランス)しか、HTML上で表示できません。)

<HTML(index1.html)上の表示>
イメージ説明

<index1.htmlのコードは下記>

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>test_list</title>
  </head>
  <body>
    <h1>{{ title }}</h1>    
    {% block content %}
        {% for list1 in list1s %}
            <p>{{list1}}</p>            
        {% endfor %}
    {% endblock %}   --!>
    </form>
  </body>

</html>

複数項目を表示(HTML上に)させる為には、HTML(index1.html)をどの様に書けば良いのでしょうか?
丸2日間、色々と試したのですが、どうしても上手くいきません。
よろしくお願いいたします。

************
2021年5月3日、TakaiYさんのアドバイスに基づき、解決しております。
最終コードは下記です。(御参考まで)

  1. pythonのコード
from flask import Flask, render_template,request
import pymysql
app = Flask(__name__)

@app.route('/', methods=['GET'])
def get():
    return render_template('index.html', \
        title = 'Form Sample(get)', \
        message = 'Where do you want to go?')


def getConnection():
    return pymysql.connect(
        host='localhost',
        db='first_db',
        user='root',
        password='yireozna',
        charset='utf8',
        cursorclass=pymysql.cursors.DictCursor
        )


@app.route('/', methods=['POST'])
def select_sql():
    connection = getConnection()
    message = "test"
    names = request.form.getlist('checkbox')

    list1s=[]
    for name in names:

        cursor = connection.cursor()
        sql = "select Country, Agency, email from tb3 where Country=%s";
        cursor.execute(sql, (name,))

        list = cursor.fetchall()
        list1s.append(list1)


    cursor.close()
    connection.close()

    print(list1s) #コンソール上で、キチンとデータが取得できているかどうかの確認用


    return render_template( 'index1.html', list1s = list1s)

if __name__ == '__main__':
    app.run()

2.index.htmlのコード

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Hello World</title>
  </head>
  <body>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
    <form action="/" method="POST" enctype="multipart/form-data">
        <div>
            <label for="ck1">Afgahanistan:</label>
            <input type="checkbox" id="ck1" name="checkbox" value="Afgahanistan">
        </div>
        <div>
            <label for="ck2">Australia:</label>
            <input type="checkbox" id="ck2" name="checkbox" value="Australia">
        </div>
        <div>
            <label for="ck3">England:</label>
            <input type="checkbox" id="ck3" name="checkbox" value="England">
        </div>
        <div>
            <label for="ck4">France:</label>
            <input type="checkbox" id="ck4" name="checkbox" value="France">
        </div>
        <div>
            <input type="submit" value="送信">
        </div>
    </form>
  </body>
</html>


3.index1.htmlのコード

ここに言語を入力
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Hello World</title>
</head>
<body>
<h1>{{ title }}</h1>   
{% block content %}        
{% for list1 in list1s %}
<p>{{loop.index}}:{{list1}}</p>
{% endfor %}        
{% endblock %} 
</form>
</body>

</html>コード
```
4.mysqlのtb3のテーブル内容

mysql> select * from tb3;
+--------------+------------+------------------+
| Country      | Agency     | email            |
+--------------+------------+------------------+
| Afgahanistan | ABC Travel | 123@gmail.com    |
| Australia    | DEF Travel | 456@yahoo.com    |
| England      | GHI Travel | 789@hotmail.com  |
| France       | JFK Travel | 1111@yahoo.co.jp |
+--------------+------------+------------------+
4 rows in set (0.00 sec)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • TakaiY

    2021/05/01 16:51

    そもそもこのコードは動かないのではありませんか?
    質問の焦点になっているはずの「list1s」がどこにも定義されていません。

    「(複数項目を選択した場合、最後にチェックした国(上記の例では、フランス)しか、HTML上で表示できません。)」となっているときのソースに差し替えてください。

    キャンセル

  • yujin1202

    2021/05/01 20:46

    早速のコメントをありがとうございます。
    大変失礼いたしました。
    Pythonファイルの下から7行目で、list1sを定義していたのですが、"s"が抜けておりました。
    従って、該当行を下記の様に修正しました。(このサイトに転記する際のミスでした。)
    また、修正後のコードで動作するのも、たった今、確認しました。
    *** list1s = cursor.fetchall() #TakaiYさんのコメントを受け、誤字修正 ***

    HTML(index1.html)の方は、一切、変えておりません。
    これで、如何でございましょうか?
    お手数をおかけしますが、教えて頂きたく。
    よろしくお願いいたします。

    キャンセル

回答 1

checkベストアンサー

+1

すくなくとも以下の場所はおかしいですね。

    for name in names:

        cursor = connection.cursor()
        sql = "select Country, Agency, email from tb3 where Country=%s";
        cursor.execute(sql, (name,))

        list1s = cursor.fetchall()
        print(list1) #コンソール上での動作確認用

※ ちなみに、最後のprintのインデントは直しています。すくなくとも元のコードはここでエラーになるはずです。

この処理は、namesにユーザが選択した国が入っていてそれをループで回していますが、list1sに追加するのでなく、その都度その結果を入れているだけなので、ループの最後の値がlist1sに設定された状態でループを抜けます。
なので、最後の国のデータしか表示されないのです。

ループの前でlist1sを空のリストとして定義してcursor.fetchall()の内容を追加していく必要があります。
追加するにあたっては、cursor.fetchall()の返り値によって、append()もしくはextend()のどちらかを使いましょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/05/03 11:32

    TakaiYさん、いつも教えてくださり、ありがとうございます。

    すいません。
    私の最初の回答が、ミスリーディングをしてしまったかも知れないのですが、最初のコードでもPythonのコンソール上では、選択した複数国はキチンと表示されております。
    しかしながら、HTML上では、最後の一か国しか表示されないのが問題となっております。

    従って、Pythonのコードではなく、HTMLの記載に問題があるのでは?と思っているのですが、
    如何でしょうか?(TakaiYさんの御回答は、Pythonのコードの方の話だと思うのですが。。。。)

    元のコードで言うと、具体的には、HTML(index1.html)の下記の部分に問題があると思っております。
    御質問ばかりで申し訳ないのですが、引き続き、教えて頂きたく。
    =========
    <body>
    <h1>{{ title }}</h1>
    {% block content %}
    {% for list1 in list1s %}
    <p>{{list1}}</p>
    {% endfor %}
    {% endblock %} --!>
    </form>
    </body>
    ==========

    キャンセル

  • 2021/05/03 12:03

    ミスリードしてないですよ。

    HTMLには問題ないと思います。「list1s」にちゃんと複数国分の情報入っていれば、このHTML(jinja)の設定で一覧が表示されるはずです。
    ただ、動かしたわけではないので、間違えている可能性はありますが、なにしろlist1sに1国分のデータしか入っていないはずなので、正しく書けていても1つしか表示されないはずです。

    また、コンソールに全ての国の情報が表示されるのは、**for文の中**にprint分があって回る度に表示されているからです。
    試しにfor文の中のprintを消して、**for文の外**(cursor.closeの後とか)にprint(list1s) をしてみると何が入っているかわかるはずです。

    キャンセル

  • 2021/05/03 13:35

    TakaiYさん、

    本当にありがとうございました!
    解決しました。
    すべての御指摘が、もっともであり、大変、勉強になりました。

    これで実装に入れます。(GW中に解決できなかったら、どうしよう?と思っていたのですが、お陰様で解決です。)
    改めて、ありがとうございました。

    最終コードを、上記質問にも追記しておきますね。(Githubにも上げようと思います。)
    勿論、ベストアンサーとさせて頂きます!
    深謝です!

    解決に役に立ったと言う意味では、特に下記コメントが有用でした。
    ================
    ① HTMLには問題ないと思います。
    → こっちに問題があると思って、Python以上によく分かってないHTMLの本を凄い勢いで読み始めていたのですが、このコメントで切り分けが出来ました!

    ②ループの前でlist1sを空のリストとして定義してcursor.fetchall()の内容を追加していく必要があります。
    → 自分で試行錯誤する時は、ループの中で空のリストを定義しておりました。確かに、for文の外でやらないとダメですね。深謝です!

    ③コンソールに全ての国の情報が表示されるのは、**for文の中**にprint分があって回る度に表示されているからです。
    試しにfor文の中のprintを消して、**for文の外**(cursor.closeの後とか)にprint(list1s) をしてみると何が入っているかわかるはずです。
    → なぜ、コンソール上ではできて、HTML上でダメなのか?がずっと分からなかったですが、printをforの「外」で書かないと切り分けができないですね。大変、有用でした!
    =====================

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • トップ
  • Pythonに関する質問
  • 【Jinja2】python+flaskを使った開発。コンソール上では表示されるデータが、HTML上で表示できない。