- changed title to orm query.update() semi-accepts InstrumentedAttributes as keys for the "values" dict
- changed milestone to 0.5.xx
orm query.update() semi-accepts InstrumentedAttributes as keys for the "values" dict
Calling update() causes an exception any time that a record is affected that was previously fetched in the same session.
Observe this example code from the documentation. The last line was added to illustrate how an exception might occur:
from sqlalchemy import *
engine = create_engine('sqlite:///:memory:', echo=True)
metadata = MetaData()
users_table = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
Column('fullname', String),
Column('password', String)
)
metadata.create_all(engine)
class User(object):
def __init__(self, name, fullname, password):
self.name = name
self.fullname = fullname
self.password = password
def __repr__(self):
return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)
from sqlalchemy.orm import mapper
mapper(User, users_table)
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
ed_user = User('ed', 'Ed Jones', 'edspassword')
session.add(ed_user)
#if this line were commented out, the next line would run successfully!
our_user = session.query(User).filter_by(name='ed').first()
#Blows up...
session.query(User).filter(User.name == 'ed').update({ User.fullname : "new fullname" })
I hope this is clear. This is the stacktrace that is produced:
File "./sa/test/lib/python2.6/site-packages/SQLAlchemy-0.5.4p2-py2.6.egg/sqlalchemy/orm/query.py", line 1704, in update
session.expire(session.identity_map[identity_key](identity_key), values.keys())
File "./sa/test/lib/python2.6/site-packages/SQLAlchemy-0.5.4p2-py2.6.egg/sqlalchemy/orm/session.py", line 959, in expire
_expire_state(state, attribute_names=attribute_names, instance_dict=self.identity_map)
File "./sa/test/lib/python2.6/site-packages/SQLAlchemy-0.5.4p2-py2.6.egg/sqlalchemy/orm/state.py", line 217, in expire_attributes
impl = self.manager[key](key).impl
KeyError: <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x27fb9d0>
Comments (4)
-
repo owner -
Account Deleted Dan Falk here. (I opened the ticket)
The reason it seems right to pass in the InstrumentedAttribute is, first of all that it can be passed in elsewhere i.e., User.name == 'ed' for example.
Second, the "User.fullname" helps to specify that it's indeed the fullname property on User and not another fullname property. I'm too new to SA, so I don't know if it supports UPDATEs on JOINs so that might not be an issue here. But if it does (or plans to), it would seem to make more sense to allow the instrumented attributes, right?
Regardless, it's good to know there's a decent workaround.
-
repo owner -
repo owner - removed milestone
Removing milestone: 0.5.7 (automated comment)
- Log in to comment
usage of query.update() is as follows:
the
InstrumentedAttribute
you are sending along works by accident here since it gets passed through to table.update() as a column, but query.update() expects it to be a string.We can either add an error message here for non-string values, or add support for columns/attributes as keys.