给定一个简单的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.name
是sqlalchemy.orm.attributes.InstrumentedAttribute
,而User.__table__.c.name
是sqlalchemy.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