根据带有标签字段的查询编辑orm对象

时间:2011-08-19 11:16:16

标签: sqlalchemy

时间更多地推动了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?

1 个答案:

答案 0 :(得分:0)

一般情况下,您必须非常小心地按照自己的方式进行更新, 因为那些视图对象PhysicalLinksDir并不总是与之同步 您可能在会话/数据库中拥有的基础DevicePhysicalLink。 我显然不了解您的要求,但在使用我的模型时,我不希望出现这种不一致的情况。

此外,您的映射类型存在问题。对于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可能会不一致。


如果理解为什么你认为这种处理你的对象的方式会更好会有用吗?这个应用程序的用例是什么?