SQLAlchemy 批量更新查询因 AttributeError 而失败
SQLAlchemy bulk update query fails with AttributeError
以下是我的模型和关系配置,(不是实际例子)
class MyUser(Base):
__tablename__ = 'my_user'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
my_user = relationship("MyUser", backref="addresses", cascade='save-update, merge')
_my_user_id = Column('my_user_id', Integer, ForeignKey('my_user.id'), nullable=True)
>>> user = db_session.query(User).get(6)
>>> add = models.Address(email='test2@test2.test2', my_user=user)
>>> db_session.add(add)
>>> db_session.commit()
>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/query.py", line 3345, in update
update_op.exec_()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1178, in exec_
self._do_pre_synchronize()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1254, in _do_pre_synchronize
query.session.identity_map.items()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1256, in <listcomp>
eval_condition(obj)]
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/evaluator.py", line 109, in evaluate
right_val = eval_right(obj)
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/evaluator.py", line 65, in <lambda>
return lambda obj: get_corresponding_attr(obj)
AttributeError: 'Address' object has no attribute 'my_user_id'
这在
时工作正常
>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'), synchronize_session=False)
>>> db_session.query(models.Address).filter_by(_my_user_id=user.id).update(values=dict(email='test3@test3.test3'))
即使在会话关闭后也能正常工作,
>> db_session.close()
>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'))
更新查询有问题吗?为什么它在其他情况下有效?
这是issue 3366 in SQLAlchemy < 1.2.x, fixed in the 1.2.x series:
The “evaluate” strategy used by Query.update()
and Query.delete()
can now accommodate a simple object comparison from a many-to-one relationship to an instance, when the attribute names of the primary key / foreign key columns don’t match the actual names of the columns. Previously this would do a simple name-based match and fail with an AttributeError
.
最简单的解决方案是升级,或者在执行批量操作时避免对 synchronizing the session 使用 "evaluate" 策略:
db_session.query(models.Address).\
filter_by(my_user=user).\
update(values=dict(email='test3@test3.test3'),
synchronize_session=False)
# ... or 'fetch'
以下是我的模型和关系配置,(不是实际例子)
class MyUser(Base):
__tablename__ = 'my_user'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
my_user = relationship("MyUser", backref="addresses", cascade='save-update, merge')
_my_user_id = Column('my_user_id', Integer, ForeignKey('my_user.id'), nullable=True)
>>> user = db_session.query(User).get(6)
>>> add = models.Address(email='test2@test2.test2', my_user=user)
>>> db_session.add(add)
>>> db_session.commit()
>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/query.py", line 3345, in update
update_op.exec_()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1178, in exec_
self._do_pre_synchronize()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1254, in _do_pre_synchronize
query.session.identity_map.items()
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 1256, in <listcomp>
eval_condition(obj)]
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/evaluator.py", line 109, in evaluate
right_val = eval_right(obj)
File "<hidden>/lib64/python3.6/site-packages/sqlalchemy/orm/evaluator.py", line 65, in <lambda>
return lambda obj: get_corresponding_attr(obj)
AttributeError: 'Address' object has no attribute 'my_user_id'
这在
时工作正常>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'), synchronize_session=False)
>>> db_session.query(models.Address).filter_by(_my_user_id=user.id).update(values=dict(email='test3@test3.test3'))
即使在会话关闭后也能正常工作,
>> db_session.close()
>>> db_session.query(models.Address).filter_by(my_user=user).update(values=dict(email='test3@test3.test3'))
更新查询有问题吗?为什么它在其他情况下有效?
这是issue 3366 in SQLAlchemy < 1.2.x, fixed in the 1.2.x series:
The “evaluate” strategy used by
Query.update()
andQuery.delete()
can now accommodate a simple object comparison from a many-to-one relationship to an instance, when the attribute names of the primary key / foreign key columns don’t match the actual names of the columns. Previously this would do a simple name-based match and fail with anAttributeError
.
最简单的解决方案是升级,或者在执行批量操作时避免对 synchronizing the session 使用 "evaluate" 策略:
db_session.query(models.Address).\
filter_by(my_user=user).\
update(values=dict(email='test3@test3.test3'),
synchronize_session=False)
# ... or 'fetch'