mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-14 20:57:19 -04:00
3cd10102e4
- 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
73 lines
2.1 KiB
Python
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()
|
|
|
|
|
|
|
|
|