簡體   English   中英

將 SqlAlchemy orm 結果轉換為字典

[英]Convert SqlAlchemy orm result to dict

如何將 SQLAlchemy orm object 結果轉換為 JSON 格式?

目前我正在使用 sqlalchemy 反射來反映數據庫中的表。 假設我有一個 User 表和一個 Address 表,我正在從數據庫中反映出來。 用戶實體與地址實體具有一對一的關系。 下面是從數據庫反映表並使用映射器 class 到 map 關系的代碼。

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 查詢 object 時

user = session.query(User).first()
user_dict = object_to_dict(user)

現在,當我想將用戶 object 轉換為字典時,我使用以下方法

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 與另一個表沒有關系,則 object_to_dict 方法可以正常工作並返回有效的 dic object。 如果用戶 object 有關系,則 object_to_dict 方法不會自動擴展關系 object 並將其轉換為字典。

誰能建議我如何自動確定返回的用戶 object 是否有關系,並將關系 object 擴展為一個字典,如果它有一個等等對於任意數量的子對象。

您可以使用映射器的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查詢。

盡管“doog adibies”的答案已經被接受並且我對它提出了支持,因為它非常有用,但算法中存在一些值得注意的問題:

  1. 關系的子序列化在第一個孩子停止(因為過早添加到“ found ”)
  2. 它還序列化后退關系,在大多數情況下這些關系是backref (如果你有一個Father對象與Son配合backref的關系,你將為其中的每個兒子生成一個額外的Father節點,其中包含與主要相同的數據Father對象已經提供!)

為了解決這些問題,我定義了另一個set()來跟蹤不需要的后退關系,之后我在代碼中移動了對被訪問孩子的跟蹤。 我還故意重命名變量,以便更清楚(當然是IMO)它們代表什么以及算法如何工作,並用更清晰的字典理解取代map()

以下是我的實際工作實現,已針對4維的嵌套對象(User - > UserProject - > UserProjectEntity - > UserProjectEntityField)進行了測試:

def model_to_dict(obj, visited_children=None, back_relationships=None):
    if visited_children is None:
        visited_children = set()
    if back_relationships is None:
        back_relationships = set()
    serialized_data = {c.key: getattr(obj, c.key) for c in obj.__table__.columns}
    relationships = class_mapper(obj.__class__).relationships
    visitable_relationships = [(name, rel) for name, rel in relationships.items() if name not in back_relationships]
    for name, relation in visitable_relationships:
        if relation.backref:
            back_relationships.add(relation.backref)
        relationship_children = getattr(obj, name)
        if relationship_children is not None:
            if relation.uselist:
                children = []
                for child in [c for c in relationship_children if c not in visited_children]:
                    visited_children.add(child)
                    children.append(model_to_dict(child, visited_children, back_relationships))
                serialized_data[name] = children
            else:
                serialized_data[name] = model_to_dict(relationship_children, visited_children, back_relationships)
    return serialized_data

基於“doog abides”和“daveoncode”的回答,以及文檔和小的更正(如“iuridiniz”所述)

https://gist.github.com/hrishikeshrt/abb610743c394ce140196498b9c4ff0b

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM