是否有一种简单的方法来遍历列名和值对?

我的SQLAlchemy版本是0.5.6

下面是我尝试使用dict(row)的示例代码:

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)

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

Traceback (most recent call last):
  File "untitled-1.py", line 37, in <module>
    print dict(u)
TypeError: 'User' object is not iterable

当前回答

Python 3.6.8 +

内置str()方法自动转换datetime。Datetime对象到iso-8806-1。

print(json.dumps([dict(row.items()) for row in rows], default=str, indent="  "))

注意:默认的func只会应用于有错误的值,所以int和float值不会被转换…除非出现错误:)。

其他回答

我只是花了几分钟来处理这个问题。 标记为正确的答案不尊重字段的类型。 解决方案来自于dictalchemy,添加了一些有趣的功能。 https://pythonhosted.org/dictalchemy/ 我刚刚测试过,工作正常。

Base = declarative_base(cls=DictableModel)

session.query(User).asdict()
{'id': 1, 'username': 'Gerald'}

session.query(User).asdict(exclude=['id'])
{'username': 'Gerald'}

假设下列函数将被添加到User类中,下面将返回所有列的所有键值对:

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

与其他答案不同的是,只有对象的那些属性被返回,这些属性是对象类级别的列属性。因此,不包括_sa_instance_state或SQLalchemy或您添加到对象中的任何其他属性。参考

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

hybrid_property延伸

如果你还想包含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)只适用于session.execute()返回的SQLalchemy行对象,而不适用于您定义要使用的类,如问题中的User类。

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

行有一个_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'}

正如@balki提到的:

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

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

然而,如果您没有指定列,则可以使用其他建议的方法之一——例如@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'}

@zzzeek在评论中写道:

注意,这是现代版本的正确答案 SQLAlchemy,假设“row”是核心行对象,而不是orm映射对象 实例。

for row in resultproxy:
    row_as_dict = row._mapping  # SQLAlchemy 1.4 and greater
    # row_as_dict = dict(row)  # SQLAlchemy 1.3 and earlier

行背景。_mapping, SQLAlchemy 1.4新增:https://docs.sqlalchemy.org/en/stable/core/connections.html#sqlalchemy.engine.Row._mapping