--- /dev/null
+"""local_session_caching.py
+
+Create a new Beaker cache type + a local region that will store
+cached data local to the current Session.
+
+This is an advanced example which assumes familiarity
+with the basic operation of CachingQuery.
+
+"""
+
+from beaker import cache, container
+import collections
+
+class ScopedSessionNamespace(container.MemoryNamespaceManager):
+ """A Beaker cache type which will cache objects locally on
+ the current session.
+
+ When used with the query_cache system, the effect is that the objects
+ in the cache are the same as that within the session - the merge()
+ is a formality that doesn't actually create a second instance.
+ This makes it safe to use for updates of data from an identity
+ perspective (still not ideal for deletes though).
+
+ When the session is removed, the cache is gone too, so the cache
+ is automatically disposed upon session.remove().
+
+ """
+
+ def __init__(self, namespace, scoped_session, **kwargs):
+ """__init__ is called by Beaker itself."""
+
+ container.NamespaceManager.__init__(self, namespace)
+ self.scoped_session = scoped_session
+
+ @classmethod
+ def create_session_container(cls, beaker_name, scoped_session):
+ """Create a new session container for a given scoped_session."""
+
+ def create_namespace(namespace, **kw):
+ return cls(namespace, scoped_session, **kw)
+ cache.clsmap[beaker_name] = create_namespace
+
+ @property
+ def dictionary(self):
+ """Return the cache dictionary used by this MemoryNamespaceManager."""
+
+ sess = self.scoped_session()
+ try:
+ nscache = sess._beaker_cache
+ except AttributeError:
+ sess._beaker_cache = nscache = collections.defaultdict(dict)
+ return nscache[self.namespace]
+
+
+if __name__ == '__main__':
+ import __init__ # if running as a script
+ import meta
+
+ # create a Beaker container type called "ext:local_session".
+ # it will reference the ScopedSession in meta.
+ ScopedSessionNamespace.create_session_container("ext:local_session", meta.Session)
+
+ # set up a region based on this new container type.
+ meta.cache_manager.regions['local_session'] ={'type':'ext:local_session'}
+
+ from model import Person
+
+ # query to load Person by name, with criterion
+ # of "person 10"
+ q = meta.Session.query(Person).\
+ options(meta.FromCache("local_session", "by_name")).\
+ filter(Person.name=="person 10")
+
+ # load from DB
+ person10 = q.one()
+
+ # next call, the query is cached.
+ person10 = q.one()
+
+ # clear out the Session. The "_beaker_cache" dictionary
+ # disappears with it.
+ meta.Session.remove()
+
+ # query calls from DB again
+ person10 = q.one()
+
+ # identity is preserved - person10 is the *same* object that's
+ # ultimately inside the cache. So it is safe to manipulate
+ # the not-queried-for attributes of objects when using such a
+ # cache without the need to invalidate - however, any change
+ # that would change the results of a cached query, such as
+ # inserts, deletes, or modification to attributes that are
+ # part of query criterion, still require careful invalidation.
+ cache, key = q._get_cache_plus_key()
+ assert person10 is cache.get(key)[0]