将sqlalchemy行对象转换为python字典

是否有一个简单的方法来迭代列名称和值对?

我的sqlalchemy版本是0.5.6

这里是我尝试使用字典(行)的示例代码,但它会抛出exception,TypeError:'用户'对象不可迭代

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) 

在我的系统输出上运行这段代码:

 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 

您可以访问SQLAlchemy对象的内部__dict__ ,如下所示:

 for u in session.query(User).all(): print u.__dict__ 

我无法得到一个好的答案,所以我使用这个:

 def row2dict(row): d = {} for column in row.__table__.columns: d[column.name] = str(getattr(row, column.name)) return d 

编辑:如果上面的function太长,不适合一些口味这里是一个class轮(python2.7 +)

 row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns} 
 for row in resultproxy: row_as_dict = dict(row) 

这是现代SQLAlchemy(v0.8 – v1.2 +)的正确答案。


使用检查系统 。

 from sqlalchemy import inspect def object_as_dict(obj): return {c.key: getattr(obj, c.key) for c in inspect(obj).mapper.column_attrs} user = session.query(User).first() d = object_as_dict(user) 

请注意.key是属性名称,可能与列名称不同,例如在以下情况下:

 class_ = Column('class', Text) 

这个方法也适用于column_property

行有一个_asdict()函数,它给出了一个字典

 In [8]: r1 = db.session.query(Topic.name).first() In [9]: r1 Out[9]: (u'blah') In [10]: r1.name Out[10]: u'blah' In [11]: r1._asdict() Out[11]: {'name': u'blah'} 
 from sqlalchemy.orm import class_mapper def asdict(obj): return dict((col.name, getattr(obj, col.name)) for col in class_mapper(obj.__class__).mapped_table.c) 

作为@balki提到:

如果您查询特定的字段,则可以使用_asdict()方法,因为它作为KeyedTuple返回。

 In [1]: foo = db.session.query(Topic.name).first() In [2]: foo._asdict() Out[2]: {'name': u'blah'} 

而如果不指定列,则可以使用其他build议的方法之一 – 例如由@charlax提供的方法。 请注意,此方法仅适用于2.7+。

 In [1]: foo = db.session.query(Topic).first() In [2]: {x.name: getattr(foo, x.name) for x in foo.__table__.columns} Out[2]: {'name': u'blah'} 

在@balki回答之后, 由于SQLAlchemy 0.8可以使用_asdict(),可用于KeyedTuple对象。 这对原来的问题提出了一个非常简单的答案。 只是,在你的例子中改变了这个最后两行(for循环):

 for u in session.query(User).all(): print u._asdict() 

这是可行的 ,因为在上面的代码中,u是类KeyedTuple的对象,因为.all ()返回KeyedTuple的列表。 因此,它有_asdict()方法,很好地返回你作为一个字典。

WRT答案由@STB:AFAIK,anithong .all()返回是一个KeypedTuple列表。 因此,只要你处理应用于查询对象的.all()的结果,上面的工作或者是指定一个列。

老问题,但是因为这是Google的“sqlalchemy row to dict”的第一个结果,所以应该有更好的答案。

SqlAlchemy返回的RowProxy对象具有items()方法: http ://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

它只是返回(键,值)元组列表。 所以可以使用以下代码将行转换为字典:

在Python中<= 2.6:

 rows = conn.execute(query) list_of_dicts = [dict((key, value) for key, value in row.items()) for row in rows] 

在Python> = 2.7:

 rows = conn.execute(query) list_of_dicts = [{key: value for (key, value) in row.items()} for row in rows] 

我find了这篇文章,因为我正在寻找一种将SQLAlchemy行转换为字典的方法。 我正在使用SqlSoup …但答案是由我自己构build的,所以,如果能帮助别人,这里是我的两分钱:

 a = db.execute('select * from acquisizioni_motes') b = a.fetchall() c = b[0] # and now, finally... dict(zip(c.keys(), c.values())) 

您正在迭代的expression式计算到模型对象列表,而不是行。 所以下面是他们的正确用法:

 for u in session.query(User).all(): print u.id, u.name 

你真的需要把它们转换成字典吗? 当然,有很多方法,但是你不需要SQLAlchemy的ORM部分:

 result = session.execute(User.__table__.select()) for row in result: print dict(row) 

更新 :看看sqlalchemy.orm.attributes模块。 它有一组函数来处理对象状态,这可能对你有用,特别是instance_dict()

请参阅Alex Brasetvik的“答案” ,您可以使用一行代码来解决问题

 row_as_dict = [dict(row) for row in resultproxy] 

在Alex Brasetvik's Answer的注释部分,SQLAlchemy的创build者zzzeek表示这是问题的“正确方法”。

假设以下函数将被添加到class User ,以下代码将返回所有列的所有键 – 值对:

 def columns_to_dict(self): dict_ = {} for key in self.__mapper__.c.keys(): dict_[key] = getattr(self, key) return dict_ 

不像其他的答案,只有对象的属性被返回,它们是对象的类级别的Column属性。 因此,不包括_sa_instance_state或任何其他属性SQLalchemy或您添加到该对象包括在内。 参考

编辑:忘记说,这也适用于inheritance的列。

hybrid_propery扩展

如果您还想要包含hybrid_property属性,则以下内容将起作用:

 from sqlalchemy import inspect from sqlalchemy.ext.hybrid import hybrid_property def publics_to_dict(self) -> {}: dict_ = {} for key in self.__mapper__.c.keys(): if not key.startswith('_'): dict_[key] = getattr(self, key) for key, prop in inspect(self.__class__).all_orm_descriptors.items(): if isinstance(prop, hybrid_property): dict_[key] = getattr(self, key) return dict_ 

我在这里假设你用开头标记Columns来指示你想要隐藏它们,要么是因为你通过hybrid_property访问属性,或者你根本不想显示它们。 参考

Tipp的 all_orm_descriptors也返回hybrid_method和AssociationProxy,如果你也想包括它们。

对其他答案的评论

每个基于__dict__属性的回答(如1,2 )都会返回对象的所有属性。 这可能是更多的属性,然后你想要的。 就像我悲伤,这包括_sa_instance_state或您在此对象上定义的任何其他属性。

基于dict()函数的每个答案(如1,2 dict()只能在session.execute()返回的SQLalchemy行对象上工作,而不能在您定义的class User ,就像问题的class User一样。

基于row.__table__.columns的求解答案肯定不行row.__table__.columns包含SQL数据库的列名称。 这些只能等于python对象的属性名称。 如果没有,你会得到一个AttributeError 。 对于基于class_mapper(obj.__class__).mapped_table.c答案(如1,2) ,它是一样的。

这是Elixir如何做的。 这个解决scheme的价值在于它允许recursion地包含关系的字典表示。

 def to_dict(self, deep={}, exclude=[]): """Generate a JSON-style nested dict/list structure from an object.""" col_prop_names = [p.key for p in self.mapper.iterate_properties \ if isinstance(p, ColumnProperty)] data = dict([(name, getattr(self, name)) for name in col_prop_names if name not in exclude]) for rname, rdeep in deep.iteritems(): dbdata = getattr(self, rname) #FIXME: use attribute names (ie coltoprop) instead of column names fks = self.mapper.get_property(rname).remote_side exclude = [c.name for c in fks] if dbdata is None: data[rname] = None elif isinstance(dbdata, list): data[rname] = [o.to_dict(rdeep, exclude) for o in dbdata] else: data[rname] = dbdata.to_dict(rdeep, exclude) return data 

我对Marco Mariani的回答有一个变化,表示为装饰者。 主要区别在于它将处理实体列表 ,以及安全地忽略一些其他types的返回值(在使用mock编写testing时非常有用):

 @decorator def to_dict(f, *args, **kwargs): result = f(*args, **kwargs) if is_iterable(result) and not is_dict(result): return map(asdict, result) return asdict(result) def asdict(obj): return dict((col.name, getattr(obj, col.name)) for col in class_mapper(obj.__class__).mapped_table.c) def is_dict(obj): return isinstance(obj, dict) def is_iterable(obj): return True if getattr(obj, '__iter__', False) else False 
 class User(object): def to_dict(self): return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")]) 

这应该工作。

我发现的最简单的方法(使用sqla 0.7.8):

 dictlist = [dict(row) for row in somequery.execute().fetchall()] 

我是一个新成立的Python程序员,并遇到与联合表格JSON的问题。 使用这里的答案的信息,我build立了一个函数来返回合理的结果给包含表名的JSON,避免了别名,或者有字段冲突。

只需传递一个会话查询的结果:

test = Session()。query(VMInfo,Customer).join(Customer).order_by(VMInfo.vm_name).limit(50).offset(10)

json = sqlAl2json(test)

 def sqlAl2json(self, result): arr = [] for rs in result.all(): proc = [] try: iterator = iter(rs) except TypeError: proc.append(rs) else: for t in rs: proc.append(t) dict = {} for p in proc: tname = type(p).__name__ for d in dir(p): if d.startswith('_') | d.startswith('metadata'): pass else: key = '%s_%s' %(tname, d) dict[key] = getattr(p, d) arr.append(dict) return json.dumps(arr) 

同样适用于inheritance类的解决scheme:

 from itertools import chain from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Mixin(object): def as_dict(self): tables = [base.__table__ for base in self.__class__.__bases__ if base not in [Base, Mixin]] tables.append(self.__table__) return {c.name: getattr(self, c.name) for c in chain.from_iterable([x.columns for x in tables])} 

有了这个代码,你也可以添加到您的查询“filter”或“join”,这项工作!

 query = session.query(User) def query_to_dict(query): def _create_dict(r): return {c.get('name'): getattr(r, c.get('name')) for c in query.column_descriptions} return [_create_dict(r) for r in query] 

在大多数情况下,列名适合他们。 但也许你写的代码如下所示:

 class UserModel(BaseModel): user_id = Column("user_id", INT, primary_key=True) email = Column("user_email", STRING) 

column.name“user_email”而字段名称是“email”时,column.name不能像以前那样正常工作。

sqlalchemy_base_model.py

我也在这里写下答案

这是一个超级简单的方法

 row2dict = lambda r: dict(r.items()) 

我没有太多的经验,但以下似乎为我在做什么工作:

 dict(row) 

这似乎太简单了(与其他答案相比)。 我错过了什么?

我利用(太多?)字典:

 def serialize(_query): #d = dictionary written to per row #D = dictionary d is written to each time, then reset #Master = dictionary of dictionaries; the id Key (int, unique from database) from D is used as the Key for the dictionary D entry in Master Master = {} D = {} x = 0 for u in _query: d = u.__dict__ D = {} for n in d.keys(): if n != '_sa_instance_state': D[n] = d[n] x = d['id'] Master[x] = D return Master 

运行瓶(包括jsonify)和flask_sqlalchemy以JSON格式输出。

用jsonify(serialize())调用函数。

适用于迄今为止我尝试过的所有SQLAlchemy查询(运行SQLite3)