query.update() does not resolve string names into expressions against the mapped class

Issue #3228 resolved
Jean-Sébastien Suzanne created an issue

Hi,

One example is better than my english.

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.hybrid import hybrid_property

engine = create_engine('sqlite:///memory')
Base = declarative_base()


class Test(Base):
    __tablename__ = 'plop'
    id = Column(Integer, primary_key=True)
    code = Column(String(64))

    @hybrid_property
    def code2(self):
        return self.code

    @code2.setter
    def code2(self, value):
        self.code = value


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

session = Session()
t = Test(code2='test')
session.add(t)
assert t.code == t.code2
t.code2 = 'other value'
assert t.code == t.code2
session.query(Test).update({'code': 'New value'})
session.query(Test).update({'code2': 'New value'})

If i can get an instance with 'code2' parameter, it would be normal to update the hybrid_property too in the query.

File "./bin/python", line 64, in <module> exec(compile(file__f.read(), __file, "exec")) File "selection.py", line 36, in <module> session.query(Test).update({'code2': 'New value'}) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/orm/query.py", line 2757, in update update_op.exec_() File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/orm/persistence.py", line 897, in exec_ self._do_exec() File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/orm/persistence.py", line 995, in _do_exec update_stmt, params=self.query._params) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/orm/session.py", line 991, in execute bind, close_with_result=True).execute(clause, params or {}) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/engine/base.py", line 729, in execute return meth(self, multiparams, params) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/elements.py", line 321, in _execute_on_connection return connection._execute_clauseelement(self, multiparams, params) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/engine/base.py", line 819, in _execute_clauseelement inline=len(distilled_params) > 1) File "<string>", line 1, in <lambda> File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/elements.py", line 492, in compile return self._compiler(dialect, bind=bind, kw) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/elements.py", line 498, in _compiler return dialect.statement_compiler(dialect, self, kw) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/compiler.py", line 395, in init Compiled.init(self, dialect, statement, kwargs) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/compiler.py", line 199, in init self.string = self.process(self.statement, compile_kwargs) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/compiler.py", line 222, in process return obj._compiler_dispatch(self, kwargs) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/visitors.py", line 80, in _compiler_dispatch return meth(self, kw) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/compiler.py", line 1806, in visit_update colparams = self._get_colparams(update_stmt, **kw) File "/Users/jssuzanne/.buildout/eggs/SQLAlchemy-0.9.7-py3.3-macosx-10.9-x86_64.egg/sqlalchemy/sql/compiler.py", line 2217, in _get_colparams (", ".join("%s" % c for c in check)) sqlalchemy.exc.CompileError: Unconsumed column names: code2

Comments (6)

  1. Mike Bayer repo owner

    use the attribute directly for now (this is preferable in any case):

    sess.query(Test).update({Test.code2: 'foo'})
    
  2. Mike Bayer repo owner
    • The :meth:.Query.update method will now convert string key names in the given dictionary of values into mapped attribute names against the mapped class being updated. Previously, string names were taken in directly and passed to the core update statement without any means to resolve against the mapped entity. Support for synonyms and hybrid attributes as the subject attributes of :meth:.Query.update are also supported. fixes #3228

    → <<cset 61a4a89d993e>>

  3. Log in to comment