¿Hay una manera simple de iterar sobre pares de nombre y valor de columna?
Mi versión de sqlalchemy es 0.5.6
Aquí está el código de muestra donde intenté usar dict (fila), pero arroja una excepción, TypeError: el objeto 'Usuario' no es iterable
import sqlalchemy
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
print "sqlalchemy version:",sqlalchemy.__version__
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
users_table = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
)
metadata.create_all(engine)
class User(declarative_base()):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, name):
self.name = name
Session = sessionmaker(bind=engine)
session = Session()
user1 = User("anurag")
session.add(user1)
session.commit()
# uncommenting next line throws exception 'TypeError: 'User' object is not iterable'
#print dict(user1)
# this one also throws 'TypeError: 'User' object is not iterable'
for u in session.query(User).all():
print dict(u)
Ejecutar este código en las salidas de mi sistema:
sqlalchemy version: 0.5.6
Traceback (most recent call last):
File "untitled-1.py", line 37, in <module>
print dict(u)
TypeError: 'User' object is not iterable
python
sqlalchemy
Anurag Uniyal
fuente
fuente
sqlalchemy.util.KeyedTuple
el objeto de fila del título de la pregunta. Sin embargo, la consulta en la pregunta usa la clase modelo (mapeada), por lo que el tipo de objeto de fila es la clase modelo en lugar desqlalchemy.util.KeyedTuple
.Respuestas:
Puede acceder al interno
__dict__
de un objeto SQLAlchemy, como el siguiente ::fuente
dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
__dict__
incluye una_sa_instance_state
entrada que luego debe eliminarse. Si actualiza a una versión futura y se agregan otros atributos, es posible que tenga que regresar y tratarlos manualmente. si desea solo datos de columna (por ejemplo, para tomar una lista de instancias de una consulta y colocarlos en un marco de datos de pandas), entonces,{col.name: getattr(self, col.name) for col in self.__table__.columns}
tal como respondió Anurag Uniyal (con correcciones importantes de los comentarios a esa respuesta) parece más sucinto y error- prueba.dict(u)
y afirma correctamente que arroja aTypeError
.No pude obtener una buena respuesta, así que uso esto:
Editar: si la función anterior es demasiado larga y no es adecuada para algunos gustos, aquí hay una línea única (python 2.7+)
fuente
return dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
.row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
para que sea un trazador de líneas real, pero prefiero que mi código sea legible, horizontalmente corto, verticalmente largox = Column('y', Integer, primary_key=True)
? Ninguna de estas soluciones funciona en este caso.return {c.name: getattr(self, c.name) for c in self.__table__.columns}
Según @zzzeek en los comentarios:
fuente
query(MyModel).all()
: El objeto MyModel no es iterable.En SQLAlchemy v0.8 y más reciente, use el sistema de inspección .
Tenga en cuenta que
.key
es el nombre del atributo, que puede ser diferente del nombre de la columna, por ejemplo, en el siguiente caso:Este método también funciona para
column_property
.fuente
sqlalchemy.inspect(obj).unloaded
las filas tienen una
_asdict()
función que da un dictfuente
como @balki mencionó:
El
_asdict()
método se puede usar si está consultando un campo específico porque se devuelve como KeyedTuple .Mientras que, si no especifica una columna, puede usar uno de los otros métodos propuestos, como el proporcionado por @charlax. Tenga en cuenta que este método solo es válido para 2.7+.
fuente
.first()
método)?Antigua pregunta, pero dado que este es el primer resultado para "sqlalchemy row to dict" en Google, merece una mejor respuesta.
El objeto RowProxy que devuelve SqlAlchemy tiene el método items (): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items
Simplemente devuelve una lista de tuplas (clave, valor). Entonces uno puede convertir una fila a dict usando lo siguiente:
En Python <= 2.6:
En Python> = 2.7:
fuente
list_of_dicts = [dict(row.items()) for row in rows]
table_name_column_name
, si desea nombres diferentes (por ejemplo, solocolumn_name
), use el.label
método.session.query( MyTable.column_name.label('column_name'), ... )
Asumiendo que las siguientes funciones se agregarán a las
class User
siguientes, se devolverán todos los pares clave-valor de todas las columnas:a diferencia de las otras respuestas, se devuelven todos los atributos del objeto, excepto los atributos del
Column
nivel de clase del objeto. Por lo tanto, no se incluye_sa_instance_state
ningún atributo SQLalchemy o cualquier otro que agregue al objeto. ReferenciaEDITAR: Olvídese de decir que esto también funciona en columnas heredadas.
hybrid_propery
extensiónSi también desea incluir
hybrid_property
atributos, funcionará lo siguiente:Supongo que aquí marca Columnas con un comienzo
_
para indicar que desea ocultarlas, ya sea porque accede al atributo mediante unhybrid_property
o simplemente no desea mostrarlas. ReferenciaTipp
all_orm_descriptors
también devuelve hybrid_method y AssociationProxy si también desea incluirlos.Observaciones a otras respuestas
Cada respuesta (como 1 , 2 ) que se basa en el
__dict__
atributo simplemente devuelve todos los atributos del objeto. Esto podría ser mucho más atributos de lo que deseas. Como triste, esto incluye_sa_instance_state
o cualquier otro atributo que defina en este objeto.Cada respuesta (como 1 , 2 ) que se basa en la
dict()
función solo funciona en objetos de fila SQLalchemy devueltos porsession.execute()
no en las clases con las que define trabajar, como elclass User
de la pregunta.La respuesta de resolución que se basa
row.__table__.columns
definitivamente no funcionará.row.__table__.columns
contiene los nombres de columna de la base de datos SQL. Estos solo pueden ser iguales al nombre de los atributos del objeto python. Si no, obtienes unAttributeError
. Para las respuestas (como 1 , 2 ) basadas enclass_mapper(obj.__class__).mapped_table.c
esto es lo mismo.fuente
fuente
Siguiendo la respuesta de @balki, desde SQLAlchemy 0.8 puede usar _asdict (), disponible para objetos KeyedTuple. Esto genera una respuesta bastante directa a la pregunta original. Simplemente, cambie en su ejemplo las dos últimas líneas (el bucle for) para esta:
Esto funciona porque en el código anterior u es un objeto de tipo clase KeyedTuple , ya que .all () devuelve una lista de KeyedTuple. Por lo tanto, tiene el método _asdict () , que devuelve muy bien u como diccionario.
Escribe la respuesta de @STB: AFAIK, y aunque .all () devuelva es una lista de KeypedTuple. Por lo tanto, lo anterior funciona si especifica una columna o no, siempre y cuando esté tratando con el resultado de .all () tal como se aplica a un objeto Query.
fuente
.all()
devuelve una lista deUser
instancias, por lo que esto no funciona.User
Las instancias no tienen un_asdict
método. Ver gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8dLa expresión que está iterando evalúa la lista de objetos modelo , no filas. Entonces, el siguiente es el uso correcto de ellos:
¿Realmente necesitas convertirlos a dictos? Claro, hay muchas maneras, pero entonces no necesitas ORM parte de SQLAlchemy:
Actualización : Echa un vistazo al
sqlalchemy.orm.attributes
módulo. Tiene un conjunto de funciones para trabajar con el estado del objeto, que puede ser útil para usted, especialmenteinstance_dict()
.fuente
Consulte la respuesta de Alex Brasetvik , puede usar una línea de código para resolver el problema
En la sección de comentarios de la Respuesta de Alex Brasetvik, zzzeek, el creador de SQLAlchemy, declaró que este es el "Método correcto" para el problema.
fuente
resultproxy
?Podrías intentar hacerlo de esta manera.
Utiliza un método incorporado en el objeto de consulta que devuelve un objeto dictonario del objeto de consulta.
referencias: https://docs.sqlalchemy.org/en/latest/orm/query.html
fuente
_asdict()
método incorporado que esencialmente comprime los nombres de campo con valores de campo y devuelve el resultado como un diccionario.u
en mi caso es una cadena, y recibo el error `` El objeto modelo '' no tiene ningún atributo '_asdict' '@hllau a continuación funcionó para míEncontré esta publicación porque estaba buscando una manera de convertir una fila SQLAlchemy en un dict. Estoy usando SqlSoup ... pero la respuesta fue creada por mí mismo, así que, si pudiera ayudar a alguien, aquí están mis dos centavos:
fuente
RowProxy
(c
en esta respuesta) se adhiere al protocolo de mapeo, por lo que puede llamardict(c)
.Puede convertir el objeto sqlalchemy en un diccionario como este y devolverlo como json / dictionary.
Funciones de ayuda:
Función del conductor:
fuente
Dos caminos:
1)
2)
fuente
Los documentos ofrecen una solución muy simple:
ResultRow._asdict()
fuente
Así es como lo hace Elixir. El valor de esta solución es que permite incluir recursivamente la representación de las relaciones en el diccionario.
fuente
¡Con este código también puede agregar a su consulta "filtro" o "unirse" y esto funciona!
fuente
Eso debería funcionar.
fuente
Tengo una variación sobre la respuesta de Marco Mariani, expresada como decoradora. La principal diferencia es que manejará listas de entidades, además de ignorar de forma segura algunos otros tipos de valores de retorno (lo cual es muy útil al escribir pruebas usando simulacros):
fuente
Para completar la respuesta de @Anurag Uniyal, aquí hay un método que seguirá recursivamente las relaciones:
fuente
d[relationship.key] = to_dict(val,with_relationships) if val else None
Con python 3.8+, podemos hacer esto con dataclass y el
asdict
método que viene con él:La clave es usar el
@dataclass
decorador y anotar cada columna con su tipo (la: str
parte de laname: str = Column(String)
línea).También tenga en cuenta que, dado que
email
no está anotado, no está incluido enquery_result_dict
.fuente
Soy un programador de Python recién creado y tuve problemas para llegar a JSON con tablas unidas. Utilizando la información de las respuestas aquí, construí una función para devolver resultados razonables a JSON, donde se incluyen los nombres de las tablas para evitar tener alias o hacer que los campos colisionen.
Simplemente pase el resultado de una consulta de sesión:
test = Session (). query (VMInfo, Customer) .join (Customer) .order_by (VMInfo.vm_name) .limit (50) .offset (10)
json = sqlAl2json (prueba)
fuente
si la columna de la tabla de modelos no es equie mysql column.
como :
Necesitará usar:
si lo usa de esta manera, puede obtener modify_time y create_time, ambos son Ninguno
Porque el nombre de los atributos de clase no es igual al almacén de columnas en mysql
fuente
Devuelve el contenido de esto: clase:
.KeyedTuple
como diccionariofuente
Por el bien de todos y de mí, así es como lo uso:
fuente
Esta función puede ayudar. No puedo encontrar una mejor solución para resolver el problema cuando el nombre del atributo es diferente a los nombres de columna.
fuente
Lo necesitará en todas partes en su proyecto, apriciado @anurag respondió que funciona bien. hasta este punto lo estaba usando, pero desordenará todo su código y tampoco funcionará con el cambio de entidad.
Más bien intente esto, herede su clase de consulta base en SQLAlchemy
después de eso, siempre que definas tu objeto, el método "as_dict" estará allí.
fuente
En la mayoría de los escenarios, el nombre de la columna es adecuado para ellos. Pero tal vez escriba el código de la siguiente manera:
el column.name "user_email" mientras que el nombre del campo es "email", el column.name no podía funcionar tan bien como antes.
sqlalchemy_base_model.py
También escribo la respuesta aquí
fuente