将SqlAlchemy ORM结果转换为dict
问题内容:
如何将SQLAlchemy orm对象结果转换为JSON格式?
当前,我正在使用sqlalchemy反射来反映数据库中的表。考虑我有一个用户表和一个地址表,我正在数据库中反映。用户实体与地址实体具有一对一的关系。下面的代码反映数据库中的表并使用mapper类映射关系。
from sqlalchemy import Table
from sqlalchemy.orm import mapper, relationship
user_reflection = Table('user', metadata, autoload=True, autoload_with=engine)
class User(object):
def __init__(self, id, name, dob):
self.id = id
self.name = name
self.dob = dob
address_reflection = Table('address', metadata, autoload=True, autoload_with=engine)
mapper(User,
user_reflection,
properties={
'address': relationship(SourceAddress, uselist=False)
}
)
现在,当我使用sqlalchemy orm查询对象时
user = session.query(User).first()
user_dict = object_to_dict(user)
现在,当我要将用户对象转换为字典时,请使用以下方法
def object_to_dict(obj):
columns = [column.key for column in class_mapper(obj.__class__).columns]
get_key_value = lambda c: (c, getattr(obj, c).isoformat()) if isinstance(getattr(obj, c), datetime) else (c, getattr(obj, c))
return dict(map(get_key_value, columns))
但是,如果返回的用户对象与另一个表没有关系,则object_to_dict方法可以正常工作并返回有效的dic对象。如果用户对象具有关系,则object_to_dict方法不会自动扩展关系对象并将其转换为dict。
谁能建议我如何自动确定返回的用户对象是否具有关系,以及如果该关系对象具有任意数量的子对象,则将该关系对象扩展为字典。
问题答案:
您可以使用映射器的Relationships属性。代码选择取决于您要如何映射数据以及关系的外观。如果您有很多递归关系,则可能要使用max_depth计数器。我下面的示例使用一组关系来防止递归循环。如果您只打算深入一遍,则可以完全消除递归,但是您确实说了“依此类推”。
def object_to_dict(obj, found=None):
if found is None:
found = set()
mapper = class_mapper(obj.__class__)
columns = [column.key for column in mapper.columns]
get_key_value = lambda c: (c, getattr(obj, c).isoformat()) if isinstance(getattr(obj, c), datetime) else (c, getattr(obj, c))
out = dict(map(get_key_value, columns))
for name, relation in mapper.relationships.items():
if relation not in found:
found.add(relation)
related_obj = getattr(obj, name)
if related_obj is not None:
if relation.uselist:
out[name] = [object_to_dict(child, found) for child in related_obj]
else:
out[name] = object_to_dict(related_obj, found)
return out
另外,请注意,还有一些性能问题需要考虑。您可能需要使用诸如joinedload或subqueryload之类的选项,以防止执行过多的SQL查询。