通过关系名称 (str) 或对象动态添加 sqlalchemy 关系
我正在解析深度嵌套的 XML 分层文件并使用 SQLAlchemy 将数据保存到 PostgreSQL。解析文件中的每个树非常简单:获取元素属性,根据命名映射对其进行重命名,创建 SQLA 对象,解析子元素,添加适当的关系(父子元素),然后重复。
为了避免样板代码,我正在尝试实现递归解决方案。到目前为止,我已经成功地实现了 SQLA 对象列表的创建,但现在努力根据预先确定的辅助字典动态添加关系(例如,我将明确说明要创建哪个关系)
非常简短的示例
<ApplicationSessionStart TradeId="085747" EventTime="2021-05-02T09:00:00">
<LotList>
<LotInfo LotNumber="1"/>
</LotList>
</ApplicationSessionStart>
SQLA 类with 关系:
class ApplicationSessionStart(Base):
__tablename__ = "application_session_start"
id = Column(Integer, primary_key=True, autoincrement="auto")
trade_id_etp = Column(String(100), nullable=False)
event_time = Column(DateTime, nullable=False)
# Relationships
lot_info = relationship(
"LotInfo",
back_populates="application_session_start",
uselist=True,
)
class LotInfo(Base):
__tablename__ = "lot_info"
id = Column(Integer, primary_key=True, autoincrement="auto")
lot_number = Column(String(5), nullable=True)
# FKs
application_session_start_id = Column(
Integer,
ForeignKey("application_session_start.id"),
)
# Relationships
application_session_start = relationship(
"ApplicationSessionStart",
back_populates="lot_info",
uselist=True,
)
描述 XML 数据逻辑的辅助字典 结构
gdm = {
"ApplicationSessionStart": {
"model": ApplicationSessionStart,
"children": {LotInfo: "LotInfo.application_session_start"},
"naming": {
"EventTime": "event_time",
"TradeId": "trade_id",
},
},
"LotInfo": {
"model": LotInfo,
"children": None,
"naming": {"LotNumber": "lot_number"},
},
}
递归创建对象的
def rec_create_class_from_elem(elem, gdm, result_list=None):
elem_name = elem.tag
expected_children = gdm.get(elem_name).get("children")
if result_list is None:
result_list = []
elem_attrs_dict = elem.attrib
elem_correct_dict = map_naming_v2(elem_name, gdm, elem_attrs_dict)
model = gdm.get(elem_name).get("model")
obj = model(**elem_correct_dict)
result_list.append(obj)
if expected_children is not None:
for k, v in expected_children.items():
model_name_str = k.__name__
for child in elem.findall(".//" + model_name_str):
rec_create_class_from_elem(child, gdm, result_list)
return result_list
函数[
、 ]
I'm parsing deeply nested XML hierarchical files and persisting data to PostgreSQL with SQLAlchemy. Parsing each tree in file is quite simple: get element attributes, rename it according to naming map, create SQLA Object, parse children elements, add appropriate relationships (parent children), repeat.
To avoid boilerplate code I'm trying to implement recursive solution. So far I've managed to implement creation of list of SQLA objects but now struggling adding relationships dinamically based on pre-determined helper dict (e.g. I will explicitly state which relationship to create)
Very shortened example
<ApplicationSessionStart TradeId="085747" EventTime="2021-05-02T09:00:00">
<LotList>
<LotInfo LotNumber="1"/>
</LotList>
</ApplicationSessionStart>
SQLA Classes with relationship:
class ApplicationSessionStart(Base):
__tablename__ = "application_session_start"
id = Column(Integer, primary_key=True, autoincrement="auto")
trade_id_etp = Column(String(100), nullable=False)
event_time = Column(DateTime, nullable=False)
# Relationships
lot_info = relationship(
"LotInfo",
back_populates="application_session_start",
uselist=True,
)
class LotInfo(Base):
__tablename__ = "lot_info"
id = Column(Integer, primary_key=True, autoincrement="auto")
lot_number = Column(String(5), nullable=True)
# FKs
application_session_start_id = Column(
Integer,
ForeignKey("application_session_start.id"),
)
# Relationships
application_session_start = relationship(
"ApplicationSessionStart",
back_populates="lot_info",
uselist=True,
)
Helper dict to describe XML data logic & structure
gdm = {
"ApplicationSessionStart": {
"model": ApplicationSessionStart,
"children": {LotInfo: "LotInfo.application_session_start"},
"naming": {
"EventTime": "event_time",
"TradeId": "trade_id",
},
},
"LotInfo": {
"model": LotInfo,
"children": None,
"naming": {"LotNumber": "lot_number"},
},
}
Function to recursively create objects
def rec_create_class_from_elem(elem, gdm, result_list=None):
elem_name = elem.tag
expected_children = gdm.get(elem_name).get("children")
if result_list is None:
result_list = []
elem_attrs_dict = elem.attrib
elem_correct_dict = map_naming_v2(elem_name, gdm, elem_attrs_dict)
model = gdm.get(elem_name).get("model")
obj = model(**elem_correct_dict)
result_list.append(obj)
if expected_children is not None:
for k, v in expected_children.items():
model_name_str = k.__name__
for child in elem.findall(".//" + model_name_str):
rec_create_class_from_elem(child, gdm, result_list)
return result_list
[<models.ApplicationSessionStart object at 0x7eff2f6be6d0>, <models.LotInfo object at 0x7eff2f6bec10>]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我发现通过调用 setattr 可以做到这一点
I've found out that this is possible by calling setattr