时间更多地推动了sqlalchemy的极限。它永远不会令人惊讶!
我有设备表,以及记录它们之间物理链接的表。
class Device(Base):
__tablename__ = "device"
device_id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(255), nullable=False)
class PhysicalLink(Base):
__tablename__ = "physical_link"
physical_links_id = sa.Column(sa.Integer, primary_key=True)
device_id_1 = sa.Column(sa.types.Integer, sa.ForeignKey(Device.device_id), nullable=False)
device_port_1 = sa.Column(sa.String(255), nullable=False)
device_id_2 = sa.Column(sa.types.Integer, sa.ForeignKey(Device.device_id), nullable=False)
device_port_2 = sa.Column(sa.String(255), nullable=False)
cable_number = sa.Column(sa.String(255), nullable=False)
当我处理已知设备的物理链接时,我不希望总是有if语句来决定我是否应该查看device_ [id | port] _ 1或2,所以我做了:
physical_links_table = PhysicalLinks.__table__
physical_links_ua = union_all(
select((
physical_links_table.c.physical_links_id,
label('this_device_id', physical_links_table.c.device_id_1),
label('this_device_port', physical_links_table.c.device_port_1),
label('other_device_id', physical_links_table.c.device_id_2),
label('other_device_port', physical_links_table.c.device_port_2),
physical_links_table.c.cable_number,
),),
select((
physical_links_table.c.physical_links_id,
label('this_device_id', physical_links_table.c.device_id_2),
label('this_device_port', physical_links_table.c.device_port_2),
label('other_device_id', physical_links_table.c.device_id_1),
label('other_device_port', physical_links_table.c.device_port_1),
physical_links_table.c.cable_number,
),),
).alias('physical_links_ua')
class PhysicalLinksDir(object):
pass
physical_links_dir_mapper = orm.mapper(PhysicalLinksDir, physical_links_ua)
physical_links_dir_mapper.add_property(
'this_device', orm.relation(Device, primaryjoin=(PhysicalLinksDir.this_device_id == Device.device_id)))
physical_links_dir_mapper.add_property(
'other_device', orm.relation(Device, primaryjoin=(PhysicalLinksDir.other_device_id == Device.device_id)))
这允许我这样做:
physical_links = (db_session
.query(PhysicalLinksDir)
.filter(PhysicalLinksDir.this_device_id = my_device.device_id)
.options(joinedload('other_device')))
for pl in physical_links:
print pl.other_device
(我是否记得告诉过你我认为那些方形的岩石!)
我需要做些什么才能修改PhysicalLinksDir实例属性,并能够将它们提交回db?
答案 0 :(得分:0)
一般情况下,您必须非常小心地按照自己的方式进行更新,
因为那些视图对象PhysicalLinksDir
并不总是与之同步
您可能在会话/数据库中拥有的基础Device
和PhysicalLink
。
我显然不了解您的要求,但在使用我的模型时,我不希望出现这种不一致的情况。
此外,您的映射类型存在问题。对于PhysicalLinksDir
的每一行,你会期望有两行PhysicalLink
(每边一行),但是如果你尝试它,你会发现情况并非如此。这样做的原因是第一列(physical_links_id
)被认为是primary_key
所以。{
查询对象将丢弃具有相同值的第二个
要修复它,您需要手动配置primary_key
。假设只能有一个
两个不同设备之间的连接,下面的解决方案将起到作用。您可能需要将其扩展为包含port
:
physical_links_dir_mapper = orm.mapper(PhysicalLinksDir, physical_links_ua,
# @note: add this
primary_key=[physical_links_ua.c.physical_links_id, physical_links_ua.c.this_device_id],
)
删除:现在,要支持delete
,您需要做的就是在PLD
与实际PhysicalLink
和{之间添加关系{1}}也会删除它代表的session.delete(my_PLD); session.commit()
:
PhysicalLink
但事实上,删除可能是开箱即用的,因为模型与physical_links_dir_mapper.add_property(
'physical_link', orm.relation(PhysicalLink, primaryjoin=(
PhysicalLinksDir.physical_links_id == PhysicalLink.physical_links_id),
foreign_keys=[PhysicalLinksDir.physical_links_id]
))
表软链接。
INSERT :嗯,直接用physical_link
对象轻松完成,所以我会这样做。
更新:您可能可能使用Session Events实现此目的,但最简单的方法是将所有属性包装在PhysicalLink
中,以便委派更改适当的对象。
重要:我仍然认为这种工作方式并不是很好,因为链接不会自动更新,而您的内存中@property
可能会不一致。
如果理解为什么你认为这种处理你的对象的方式会更好会有用吗?这个应用程序的用例是什么?