web-dev-qa-db-ja.com

DictCursorはpsycopg2で動作しないようです

以前にpsycopg2を使用したことはありませんが、fetchallまたはfetchoneがリストではなく辞書を返すように、カーソルファクトリをDictCursorに変更しようとしています。

テストスクリプトを作成して、物事を単純にし、この機能のみをテストしました。ここに私が動作するはずだと思う私のちょっとしたコードがあります

import psycopg2
import psycopg2.extras

conn = psycopg2.connect("dbname=%s user=%s password=%s" % (DATABASE, USERNAME, PASSWORD))

cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
cur.execute("SELECT * from review")

res = cur.fetchall()

print type(res)
print res

Res変数は常にリストであり、予想どおりの辞書ではありません。

私が実装した現在の回避策は、辞書を作成し、fetchallによって返された各行を実行するこの関数を使用することです。

def build_dict(cursor, row):
    x = {}
    for key,col in enumerate(cursor.description):
        x[col[0]] = row[key]
    return d

Pythonはバージョン2.6.7で、psycopg2はバージョン2.4.2です。

51
Jim
res = cur.fetchall()

respsycopg2.extras.DictRowsのリストにします。


または、cur.fetchallを呼び出す代わりに、curが反復可能であることを利用できます。

cur.execute("SELECT * from review")
for row in cur:
    print(row['column_name'])

したがって、dictのような構文でデータにアクセスできます。

27
unutbu

RealDictCursorを使用します。

cur = conn.cursor(cursor_factory = psycopg2.extras.RealDictCursor)
cur.execute("SELECT * from review")
res = cur.fetchall()    

これにより、「advanced psycopg2 list」ではなく、real python辞書としての行を含むリストが表示されます。

91
kerma

別の解決策は、 Named Tuple Cursor を使用することです。これは、Real Dict Cursorが、ドキュメントで説明されているように、整数インデックスを使用するクエリを中断するためです。

名前付きタプルカーソルを使用すると、次のようなドット構文でアクセスできます。

import psycopg2
import psycopg2.extras
cur = conn.cursor(cursor_factory = psycopg2.extras.NamedTupleCursor)
cur.execute("SELECT * from review")
res = cur.fetchone()
res.key1
res.key2

これは物事を整頓し、私の知る限り何も壊しません。

7
Brideau

これは古い質問ですが、まだグーグルで出てきているので、ビッグGから来ている人のためにこれに自分のコードを追加すると思いました。

私にとっては、辞書に戻したい複数の行があり、データベースのフィールドからキーを設定するためにループなどを使用したくないことが理想的です。

したがって、dict comprehension syntax私は次のことができます。

ディクショナリへのテーブル行


pgCursor = Conn.cursor(cursor_factory = psycopg2.extras.RealDictCursor)
pgCursor.execute("SELECT * FROM tablename;",([]))
dictRows = {n['id']: n for n in pgCursor}

関数と呼び出し

#NOTE this is using a class object hence the self param
def DBTableToDictByID(self, squery):
    self.Pointer.execute(squery,([]))
    return {n['id']: n for n in self.Pointer}

dictRows = self.DBTableToDictByID("SELECT * FROM tablename;")

これはfor x in yループを使用していますが、私が知る限りそのPythonic ....うまくいけば、これは世の中の助けになるでしょう。

3
Angry 84

答えで行われているように、RealDictCursor機能を使用することに加えて、すべての列を選択する必要があります(選択後に*記号を使用)。

WHERE条件で既に使用されている既知の値があるため、結果の一部の列には興味がありませんでした。しかし、SELECT (..., ..., ..., ...) FROM ... WHERE ...バリアントは辞書をくれませんでした。

宜しくお願いします !ハーレー

0
Hans Davidson

したがって、これをmysqlバージョンのディクショナリカーソルのように機能させるには、別の関数またはコードでラップする必要があります。フォーラムに行き、fetchall()呼び出しがDictionary Cursorで使用されたときに辞書を返すコードの今後の展開のために、これを提案します。修正に使用できるサンプルコードを次に示します。

cursor.execute(query)
# Python 2.7 and beyond with dictionary comprehension
results = [{key:value for key,value in row.iteritems()} for row in cursor]
# Python 2.6 and before
# results = [dict((key,value) for key,value in row.iteritems()) for row in cursor]

このコードは、fetchall()を使用して、MySQLバージョンの辞書カーソルと同じ形式にします。彼らがそれを異なって実装した理由はわかりませんが、これはfetchall()の場合のリストではなく、実際のpython辞書の同じ出力を得るのに役立ちます。

0
Josh Williams