InstrumentedAttribute vs Column in update() clause in SqlAlc



给定一个简单的ORM定义,

class User(Base):
    __tablename__ = 'users'
    id = sql.Column(sql.Integer, primary_key=True)
    name = sql.Column(sql.String)

以下更新行的两种方法之间有什么区别?

方法1

connection.execute(
    User.__table__.update()
    .where(User.name='Alice')
    .values(name='Bob')
)

方法2

connection.execute(
    User.__table__.update()
    .where(User.__table__.c.name='Alice')  # <-- Difference
    .values(name='Bob')
)

User.namesqlalchemy.orm.attributes.InstrumentedAttribute,而User.__table__.c.namesqlalchemy.sql.schema.Column

我发现使用第二种方法的 SqlAlchemy 文档,但第一种方法也有效吗?

我的回答可能并不详尽,但我注意到至少有一个区别:

在方法#1中:键将是一个对象,其中__repr__()将显示类似 <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7f03e93b77c0> .

这在单元测试中可能会出现问题,例如,当使用模拟和assert_called_with()失败时。在这种情况下,你会得到类似这样的信息:

AssertionError: expected call not found.
Expected: some_db_method({<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a940e0>: 1, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a94400>: <ANY>, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a945e0>: "something", <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a94180>: None}, {<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a945e0>: <ANY>})
Actual: some_db_method(<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a940e0>: 1, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a94400>: <ANY>, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a945e0>: "something", <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7fed04a94180>: None}, {<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x8fef13a123f5>: <ANY>})

这可能更难阅读和调试。

如果您仍然喜欢方法 #2,仍然有一种方法可以以更用户友好的方式显示列:

from sqlalchemy.orm.attributes import InstrumentedAttribute
def _debug_columns_repr(self: InstrumentedAttribute):
    return f"{self.table.name}.{self.name}"
InstrumentedAttribute.__repr__ = _debug_columns_repr

最新更新