Files
sqlalchemy/examples/query_caching/query_caching.py
T
Mike Bayer 3cd10102e4 - Query.UpdateDeleteTest.test_delete_fallback fails on mysql due to subquery in DELETE; not sure how to do this exact operation in MySQL
- added query_cls keyword argument to sessionmaker(); allows user-defined Query subclasses to be generated by query().
- added @attributes.on_reconstitute decorator, MapperExtension.on_reconstitute, both receieve 'on_load' attribute event allowing
non-__init__ dependent instance initialization routines.
- push memusage to the top to avoid pointless heisenbugs
- renamed '_foostate'/'_fooclass_manager' to '_sa_instance_state'/'_sa_class_manager'
- removed legacy instance ORM state accessors
- query._get() will use _remove_newly_deleted instead of expunge() on ObjectDeleted, so that transaction rollback
restores the previous state
- removed MapperExtension.get(); replaced by a user-defined Query subclass
- removed needless **kwargs from query.get()
- removed Session.get(cls, id); this is redundant against Session.query(cls).get(id)
- removed Query.load() and Session.load(); the use case for this method has never been clear, and the same functionality is available in more explicit ways
2008-06-09 01:24:08 +00:00

73 lines
2.1 KiB
Python

from sqlalchemy.orm.query import Query, _generative
from sqlalchemy.orm.session import Session
# the cache. This would be replaced with the caching mechanism of
# choice, i.e. LRU cache, memcached, etc.
_cache = {}
class CachingQuery(Query):
# generative method to set a "cache" key. The method of "keying" the cache
# here can be made more sophisticated, such as caching based on the query._criterion.
@_generative()
def with_cache_key(self, cachekey):
self.cachekey = cachekey
# single point of object loading is __iter__(). objects in the cache are not associated
# with a session and are never returned directly; only merged copies.
def __iter__(self):
if hasattr(self, 'cachekey'):
try:
ret = _cache[self.cachekey]
except KeyError:
ret = list(Query.__iter__(self))
for x in ret:
self.session.expunge(x)
_cache[self.cachekey] = ret
return iter(self.session.merge(x, dont_load=True) for x in ret)
else:
return Query.__iter__(self)
# example usage
if __name__ == '__main__':
from sqlalchemy import Column, create_engine, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Session = sessionmaker(query_cls=CachingQuery)
Base = declarative_base(engine=create_engine('sqlite://', echo=True))
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(100))
def __repr__(self):
return "User(name=%r)" % self.name
Base.metadata.create_all()
sess = Session()
sess.add_all(
[User(name='u1'), User(name='u2'), User(name='u3')]
)
sess.commit()
# cache two user objects
sess.query(User).with_cache_key('u2andu3').filter(User.name.in_(['u2', 'u3'])).all()
sess.close()
sess = Session()
# pull straight from cache
print sess.query(User).with_cache_key('u2andu3').all()