【问题标题】:Edit orm object based on query with label fields根据带有标签字段的查询编辑 orm 对象
【发布时间】:2011-10-30 13:12:35
【问题描述】:

是时候进一步突破 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

(我记得告诉过你我认为 sqlalchmey 很摇滚吗!)

问题

我需要做什么才能修改 PhysicalLinksDir 实例属性,并能够将它们提交回数据库?

【问题讨论】:

  • 您希望能够修改哪些属性?您是否还希望能够使用此“PhysicalLinksDir”添加/删除链接?
  • 我想基本编辑所有属性 - [this_device_port, other_device_id, other_device_port, cable_number] 我想添加和删除。

标签: sqlalchemy


【解决方案1】:

一般来说,您必须非常小心地以您想要的方式更新它, 因为那些视图对象PhysicalLinksDir 并不总是与 基础DevicePhysicalLink 您可能在会话/数据库中。 我显然不知道您的要求,但我不希望在使用我的模型时出现这种不一致。

此外,您的映射类型也存在问题。您可能希望每行 PhysicalLink 有 2 行 PhysicalLinksDir(每侧一个),但如果您尝试一下,您会发现情况并非如此。原因是第一列 (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:现在,要支持delete,您只需在PLD 和实际PhysicalLink 之间添加关系,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]
    ))

但实际上,由于模型软链接到physical_link 表,因此删除可能会立即生效。

INSERT:嗯,这很容易直接使用PhysicalLink 对象完成,所以我会保持这种方式。

更新:您可能会使用Session Events 实现此目的,但最简单的方法是将所有属性包装在@property 中,这会将更改委托给正确的对象.

重要提示:我仍然认为这种工作方式不是很好,因为链接不会自动更新,并且您的内存中 UnitOfWork 可能不一致。


是否也有助于理解为什么您认为这种处理对象的方式会更好?这个应用的用例是什么?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    相关资源
    最近更新 更多