🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

9165閲覧

Flask / psycopg2でfetchallを利用した際に取得されるデータの構造がわからない

baboo

総合スコア8

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/01/16 01:59

編集2021/01/16 02:00

#実現したいこと
・Flask及びpsycopg2にてfetchallを利用した際、取得したデータの型を知りたい

#現状
下記のソースコードを元にpython,Flask,PostgreSQLについて学習しております。
その過程で、なぜそのコードで希望した出力がなされるのか、がわからなくなってしまったため、質問させていただけますと幸いです。

#ソースコード及び不明点

python

1#モジュールのインポート 2from flask import Flask, render_template, request 3import psycopg2 4import psycopg2.extras 5 6#インスタンス化 7app = Flask(__name__) 8 9#コネクションの作成 10conn = psycopg2.connect(""" 11 user=flasklearner 12 dbname=flasknote 13""") 14 15#カーソルの作成 16cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) 17 18#ルーティング 19@app.route('/', methods=['GET']) 20def index(): 21 cur.execute('SELECT * FROM messages') 22 messages = cur.fetchall() 23 messages = [ dict(message) for message in messages ] 24 return render_template('index.html', messages=messages)

html

1<!doctype html> 2<html> 3 <head> 4 <meta charset="utf-8"/> 5 </head> 6 <body> 7 <div> 8 {% for msg in messages %} 9 <h2>{{msg.username}}</h2> 10 <p>{{msg.message}}</p> 11 {% endfor %} 12 </div> 13 </body> 14</html>

SQL

1CREATE TABLE messages ( 2 username varchar(64), 3 message varchar(140) 4); 5

※上記のコードからは消していますが、データはフォームから入力されたものをINSERT INTOでレコード作成しています。

不明点としてはcur.fetchall()で取得したデータ型が何であるか、といった内容になります。
自分の現状の認識は、

python

1cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

の部分にて、カーソル作成時に通常配列形式で取得される情報を辞書型で返されるように指定し、

python

1cur.execute('SELECT * FROM messages') 2messages = cur.fetchall()

にてテーブルに存在する全てのレコードを取得、そしてそれをmessagesに格納している、と思っています。
【不明点1】ここでmessagesには下記のような各レコードごとの辞書データのリストが入っているのでしょうか?

[{"username":"入力した値1", "message":"入力した値1"}, {"username":"入力した値2", "message":"入力した値2"}, ... , {"username":"入力した値N", "message":"入力した値N"}]

【不明点2】またその後の下記部分では何を行い、最終的にindex.html側でmsg.usernameとして中身が取り出せるのか、もわかっておりません。。。

Python

1messages = [ dict(message) for message in messages ]

初歩的な質問で恐縮ですが、お力添えいただけますと幸いです。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

不明点 1 について

print() してみましょう!

Python

1>>> print(items[0]) 2[1, '0000000001', 'テスト商品1', datetime.datetime(2021, 1, 16, 11, 36, 48, 60724)]

なんとただのリストが返ってきました。カラム情報はどこへ行ってしまったのか……。ここで type() をしてみると

Python

1>>> type(items[0]) 2<class 'psycopg2.extras.DictRow'>

なにやら組み込みの list とは違うクラスがでてきましたね。これを dir() にかけてみましょう。

Python

1>>> dir(items[0]) 2['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_index', 'append', 'clear', 'copy', 'count', 'extend', 'get', 'index', 'insert', 'items', 'keys', 'pop', 'remove', 'reverse', 'sort', 'values']

よーくみると keys というのが入ってます。リストっぽい見た目のくせして dict のメソッドを持っています!keys() を早速実行してみると

Python

1>>> items[0].keys() 2<odict_iterator object at 0x7fcbe5cd5360> 3>>> list(items[0].keys()) 4['id', 'item_cd', 'name', 'created']

出ました!カラム名です!こんな感じで各々の列からカラム名を参照できるんですね。ただこれだと列ごとにカラム名持ってて効率悪くない?と思いませんか?ここからはコード読みにいったら途中から C のコードになって諦めてしまったので霊感で語るんですが、多分内部でクエリごとのカラム名をキャッシュしておいて、カラム名をリクエストされたらそのキャッシュを返すような仕組みになっているんではなかろーかという予想です。実際のデータも for で回したり list にするまでは内部的には違うオブジェクト扱いで、高速化がなされている、というのが予想です。

不明点 2 について

前述のように各データは DictRow という特殊なオブジェクトになっているのでした。これを dict() にかけてみましょう。

Python

1>>> dict(items[0]) 2{'id': 1, 'item_cd': '0000000001', 'name': 'テスト商品1', 'created': datetime.datetime(2021, 1, 16, 11, 36, 48, 60724)}

なんと、ディクショナリが返ってきましたね。実は dict は一定の条件を満たせばオブジェクトも渡すことが出来ます。
組み込み型 — Python 3.9.1 ドキュメント
DictRow__getitem__() メソッドと keys() を持っているので dict() に渡すとディクショナリにすることが出来ます。あとはリスト内包表記で各列の DictRow に対し dict をかけていけばディクショナリの配列として受け取ることが出来ます。このようにして Django で messagesfor で回しながら msg で参照することが出来ます。

投稿2021/01/16 04:48

A_kirisaki

総合スコア2853

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

baboo

2021/01/16 11:14

A_kirisakiさん こちら前回に続き回答いただきありがとうございます! kirisakiさんに前回ご回答いただいたことで現在Flaskを勉強中です! いただいたご回答について、まずは何より詳細ご説明いただきありがとうございます! その上で疑問に思ったことがいくつかありますので、もしよろしければお教えいただけると嬉しいです・・・! 【不明点1に関して】 (質問1) ご回答にあったitemsはkirisakiさんの方で作成されたDBのレコードを下記のように受けとった変数でしょうか? ```Python cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur.execute('SELECT * FROM [テーブル名]') items = cur.fetchall() ``` (質問2) 自分の方で書かせていただいたコードのmessagesは(また質問1が正であった際、kirisakiさんの方でご用意いただいたitemsは)list型でもdict型でもなく、psycopg2.extras.DictRow型というpsycopg2で定義している型(クラス)ということでしょうか? またpsycopg2.extras.DictRow型は要素番号を指定すると各レコードごとの値が取得でき、また.keysメソッドを利用することで各要素(各レコードの値)からカラム名のリスト(?)へアクセスできる、ということでしょうか? (質問3)※これはあまり本件とは関係ないかもです・・・ 今回のitemsのように処理自体がローカルサーバーを起動して行う場合(手元のエディターでコンパイルするのみではない場合?)、printの結果はどこに出力されるのでしょうか・・・? VScodeなどでコンパイルした際には標準出力でターミナルで確認できると思うのですが、今回のような場合もprintで結果がみれるならデバッグしやすくてよいな・・・と思ってます。 質問が多くて恐縮です・・・
A_kirisaki

2021/01/16 11:22

1. そうです。はしょちゃって伝わりにくかったですね。 2. そういうことです。list であり dict でもあるみたいな特殊なクラスですね。 3. あまり VSCode は触ったことがないので正確なことは言えないんですが、多分ターミナルが付いてると思うんでそこで python を起動しちゃいます。何もオプションがないと repl(Read-Eval-Print Loop) という対話型のシェルが開きます。そうすると例のように >>> と出るので変数を打ち込むと中身を表示してくれたりします。import とかもできるので自分が作った関数のテストとかも出来ます(でもそれは本当は自動テストを書いたほうがよいかも)。
baboo

2021/01/16 11:44

kirisakiさんお返事ありがとうございます! 質問3つともご回答いただき、そして内容も理解できました! いつも本当にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問