2011-07-18 17 views
36

No he trabajado anteriormente con psycopg2, pero estoy intentando cambiar la fábrica del cursor a DictCursor para que fetchall o fetchone devuelvan un diccionario en lugar de una lista.DictCursor no parece funcionar en psycopg2

Creé un script de prueba para hacer las cosas más simples y solo compruebo esta funcionalidad. Aquí está mi pequeño pedazo de código que creo que debería trabajar

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 resolución variable es siempre una lista y no un diccionario lo que cabe esperar.

Una solución actual que he implementado es utilizar esta función que crea un diccionario y ejecuta cada fila devuelta por fetchall a través de él.

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

Python es la versión 2.6.7 y psycopg2 es la versión 2.4.2.

Respuesta

20
res = cur.fetchall() 

hace res una lista de psycopg2.extras.DictRow s.


Como alternativa, en lugar de llamar cur.fetchall se puede aprovechar el hecho de que cur es un iterable:

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

y así podrás acceder a los datos con dict -como sintaxis.

+0

Gracias, creo que estás al tanto con "dict-like". Es una lista pero actúa como un diccionario. Parece una decisión de diseño extraña, pero al menos está funcionando ahora. Gracias de nuevo. – Jim

+12

@Seth: si quieres un diccionario real, utiliza el acertadamente llamado 'RealDictCursor'. –

+0

@Seth: un diccionario no tiene orden por lo que ya no puede usarlo como una tupla, la primera columna en la consulta ya no sería 'row [0]' sino algo arbitrario. Así que hay algunos méritos :) – Wolph

64

Uso RealDictCursor:

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

Esto le da una lista con filas como diccionarios de Python reales en lugar de "lista psycopg2 avanzado".

+1

Gracias. Funciona bien. – ibi0tux

+1

Sí esto funciona .. Archivado como error en el plugin de la botella https://github.com/raisoblast/bottle-pgsql/issues/2 – PedroMorgan

0

Además de utilizar la función RealDictCursor, también puede tener que solicitar todas las columnas (utilizando el símbolo * después de seleccionar), como se hace en la respuesta.

No me interesaron algunas columnas del resultado, ya que tenían valores conocidos ya utilizados en DONDE. Pero la variante SELECT (..., ..., ..., ...) FROM ... WHERE ... no me dio diccionarios.

¡Un cordial saludo! Harley

+0

Deje fuera el paréntesis y su consulta funciona: 'SELECT ..., ..., ..., ... DE ... DONDE ... '. –

5

Otra solución sería usar el Named Tuple Cursor ya que el Real Dict Cursor romperá cualquier consulta que use índices enteros como se explica en su documentación.

con los cursores tupla con nombre, puede acceder a ellos con la sintaxis con punto de este modo:

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 

Esto mantiene las cosas ordenadas y no romper nada por lo que yo sé.

+0

Además, el resultado completo se puede convertir a una lista de dictados como este: '[row._asdict() para row in cur]' – GetFree

3

Si bien esta es una pregunta más antigua, todavía aparece en Google por lo que pensé que iba a añadir mi código a este para cualquier otra persona que viene de la gran G.

Para mí, tengo varias filas que lo haría Me gusta regresar a un diccionario e idealmente no quiero usar un bucle o similar para establecer la clave desde un campo en la base de datos.

Entonces, usando dict comprehension syntax puedo hacer lo siguiente.

filas de tabla al diccionario


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

& Función de llamarlo

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

Si bien esto está usando un ciclo for x in y, es pitónico por lo que puedo decir ... Espero que esto ayude a algunos por ahí.

0

Para que esto funcione como la versión mysql del cursor del diccionario, deberá envolverlo en otra función o código. Voy a ir a los foros y sugerirles esto para futuras implementaciones de su código para devolver un diccionario cuando se usa la llamada fetchall() con el Cursor de diccionario. Aquí hay un código de ejemplo que se utiliza para fijar por ello:

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] 

Este código hace que sea el mismo formato que la versión de MySQL del cursor utilizando el diccionario de fetchall(). No estoy seguro de por qué lo implementaron de manera diferente, pero esto le ayudará a obtener el mismo resultado de un diccionario de python real en lugar de una lista en el caso de fetchall().

Cuestiones relacionadas