如何将SQLAlchemy的行对象转换为Python字典?
如何将SQLAlchemy的行对象转换为Python字典?
有没有一种简单的方法来遍历列名和值对?
我使用的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() # 取消下一行的注释会抛出异常'TypeError: 'User' object is not iterable' #print dict(user1) # 这一行也会抛出'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, inprint dict(u) TypeError: 'User' object is not iterable
在评论中提到,这是适用于现代版本SQLAlchemy的正确答案,假设"row"是一个核心行对象,而不是ORM映射的实例。
for row in resultproxy: row_as_dict = row._mapping # SQLAlchemy 1.4及更高版本 # row_as_dict = dict(row) # SQLAlchemy 1.3及更早版本
关于`row._mapping`的背景,SQLAlchemy 1.4的新功能:https://docs.sqlalchemy.org/en/stable/core/connections.html#sqlalchemy.engine.Row._mapping
问题出现的原因是出现了"XXX对象不可迭代"的错误,我正在使用0.5.6版本,通过session.query(Klass).filter().all()获取结果。
Uniyal:请使用最小的代码片段展示出问题,并附上真实的错误回溯信息。通过评论和代码摘要很难做到这一点。
请查看更新的代码,我使用了你提到的链接中给出的相同示例,我也没有看到那里使用了dict?
请注意,这是适用于现代版本SQLAlchemy的正确答案,假设"row"是一个核心行对象,而不是ORM映射的实例。
还请注意,zzzeek是SQLAlchemy的创建者。
有人知道为什么这样做可以吗?RowProxy并没有继承自collections.Mapping, dict, collections.OrderedDict()或collections.UserDict()
。而我找到的dict
构造函数的描述似乎都不适用。
有人能详细解释一下吗?我是个新手,不太明白。
你说得对,它确实没有继承那些类型,但它实现了__getitem__
和keys
等方法,因此它看起来像一个映射。 github.com/sqlalchemy/sqlalchemy/blob/…
是的,没错。 docs.python.org/3.7/glossary.html#term-mapping
核心行对象与ORM映射实例有什么区别?这对我从query(MyModel).all()
的行不起作用:MyModel对象不可迭代。
我尝试过这样做,但当你有许多字段具有相同的名称时,你会得到奇怪的结果。例如,在原始查询中加入两个表,如"Select a.*, b.* from A a, B b"
这个答案不够有帮助,因为你没有说明"resultproxy"是什么或怎么使用它?
resultproxy
只是一个代理变量名,代表你的结果变量。将其替换为适当的查询结果变量。
请注意,row._mapping
返回的是一个RowMapping而不是一个dict。如果想要添加键或进行其他dict操作,需要将其转换为dict。
鉴于我们处于2022年,SQLAlchemy 1.4已经成熟,即将推出2.0版本,应该将此答案标记为正确答案。
Python的约定是不依赖"_anything",因为它是保留的。为什么在SQLAlchemy中这是正确的做法?
如何将SQLAlchemy行对象转换为Python字典?
在这段代码中,作者遇到了一个问题,即如何将SQLAlchemy的行对象转换为Python字典。他们试图寻找一个好的答案,但没有找到一个满意的解决方案。因此,他们提供了一个自定义的函数row2dict
来解决这个问题。该函数遍历行对象的每个列,并将列名作为键,将列值转换为字符串并作为值存储在字典中。
作者还添加了一行代码,以提供一个更简洁的解决方案,即使用lambda函数和字典推导式来实现相同的功能。这个一行代码的解决方案使用相同的原理,只是将代码压缩到一行中。
然后,其他人提供了一些改进的建议,例如使用return dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
来更简洁地实现相同的功能。
此外,有人提出了一个问题,即如果列没有分配给相同名称的属性会怎么样。在这种情况下,原始的解决方案将不起作用。为了解决这个问题,有人建议使用{c.name: getattr(self, c.name) for c in self.__table__.columns}
来避免使用columns.keys()
。
另外还有一些评论指出了原始解决方案的一些问题,例如它无法处理使用_property
定义的列,以及它返回值为字符串而不是原始类型的问题。
最后,有人提供了一个更新的解决方案{c.expression.name: getattr(obj, c.key) for c in inspect(obj).mapper.column_attrs}
,这个解决方案将数据库列名作为字典键,而不是使用属性名。
最新版本的SQLAlchemy允许直接使用row.columns
来实现相同的功能。
为了将SQLAlchemy的行对象转换为Python字典,作者提供了一个自定义函数,并收到了其他人的改进建议和解决方案。这些解决方案使用不同的方法来实现相同的目标,并解决了一些潜在的问题。
如何将SQLAlchemy的行对象转换为Python字典?
在这个问题中,用户想要将SQLAlchemy的行对象转换为Python字典。他们尝试了一些方法,但是遇到了一些问题。下面是一些相关的讨论和解决方法:
- 一个用户建议使用row对象的__dict__
属性来获取内部字典表示。他们给出了一个例子:for u in session.query(User).all(): print u.__dict__
,但也指出这种方法会多出一个_sa_instance_state
字段。
- 另一个用户解释了为什么多出的_sa_instance_state
字段是一个问题,并提供了一个更好的解决方法:dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
。这种方法在获取字典后手动删除了多余的字段。
- 有人认为这种方法不够理想,因为__dict__
包含了_sa_instance_state
字段,如果未来版本中添加了其他属性,可能需要手动处理它们。他们提供了另一种更简洁和错误防范的方法:{col.name: getattr(self, col.name) for col in self.__table__.columns}
。
- 还有其他一些用户提供了类似的解决方法,例如:{k: v for k, v in item.__dict__.iteritems() if not str(k).startswith("_")}
。
总之,用户试图找到一种将SQLAlchemy行对象转换为Python字典的方法。他们尝试了使用__dict__
属性,但遇到了一些问题。其他用户提供了一些解决方法,包括手动删除多余字段和使用更简洁和错误防范的方法来获取字典。