web-dev-qa-db-fra.com

DictCursor ne semble pas fonctionner sous psycopg2

Je n'avais jamais travaillé avec psycopg2 auparavant, mais j'essaie de modifier la fabrique de curseurs en DictCursor afin que fetchall ou fetchone renvoie un dictionnaire plutôt qu'une liste.

J'ai créé un script de test pour simplifier les choses et ne tester que cette fonctionnalité. Voici mon petit morceau de code qui, à mon avis, devrait fonctionner

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

La variable res est toujours une liste et non un dictionnaire comme je l’attendrais.

Une solution de contournement que j'ai implémentée consiste à utiliser cette fonction qui crée un dictionnaire et exécute chaque ligne renvoyée par fetchall.

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

Python est la version 2.6.7 et psycopg2 est la version 2.4.2.

47
Jim
res = cur.fetchall()

fait res une liste de psycopg2.extras.DictRows. 


Sinon, au lieu d'appeler cur.fetchall, vous pouvez tirer parti du fait que cur est un itérable:

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

ainsi, vous pourrez accéder aux données avec une syntaxe semblable à dict.

26
unutbu

Utilisez RealDictCursor: 

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

Cela vous donne une liste avec des lignes comme de vrais dictionnaires python au lieu de "liste psycopg2 avancée".

85
kerma

Une autre solution consisterait à utiliser le Curseur de tuple nommé , car le curseur Real Dict cassera toute requête utilisant des indicateurs entiers comme expliqué dans sa documentation.

Avec les curseurs de tuple nommés, vous pouvez y accéder avec la syntaxe à points comme ceci:

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

Cela garde les choses en ordre et ne casse rien autant que je sache.

6
Brideau

Bien qu'il s'agisse d'une question plus ancienne, elle est toujours abordée dans Google. Je pensais donc que j'ajouterais mon code à toute personne venant du grand G.

Pour moi, j'ai plusieurs lignes que je voudrais revenir dans un dictionnaire et, idéalement, ne pas vouloir utiliser une boucle ou similaire pour définir la clé à partir d'un champ de la base de données .. 

Donc, en utilisant dict comprehension syntax je peux faire ce qui suit.

Tables dans le dictionnaire


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

Fonction & Appeler

#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;")

Bien que cela utilise une boucle for x en y, sa Pythonic pour autant que je sache ... Espérons que cela aidera certaines personnes.

3
Mayhem

En plus d'utiliser la fonctionnalité RealDictCursor, vous devrez peut-être également demander toutes les colonnes .__ (à l'aide du symbole * après sélection), comme dans la réponse.

Certaines colonnes du résultat ne m'intéressaient pas, car elles avaient des valeurs connues Déjà utilisées dans les conditions WHERE. Mais la variante SELECT (..., ..., ..., ...) FROM ... WHERE ... Ne m'a pas donné de dictionnaire.

Cordialement, Harley

0
Hans Davidson

Donc, pour que cela fonctionne comme la version mysql du curseur de dictionnaire, vous devrez l’envelopper dans une autre fonction ou un autre code. Je vais aller sur les forums et leur suggérer cela pour les déploiements futurs de leur code pour renvoyer un dictionnaire lorsque l'appel fetchall () est utilisé avec le curseur du dictionnaire. Voici un exemple de code que vous pouvez utiliser pour y remédier:

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]

Ce code en fait le même format que la version MySQL du curseur de dictionnaire utilisant fetchall (). Vous ne savez pas pourquoi ils l'ont implémenté différemment, mais cela vous aidera à obtenir le même résultat qu'un dictionnaire python réel plutôt qu'une liste dans le cas fetchall ().

0
Josh Williams