--- /dev/null
+"""Illustrates how to place a dictionary-like facade on top of a dynamic_loader, so\r
+that dictionary operations (assuming simple string keys) can operate upon a large \r
+collection without loading the full collection at once.\r
+\r
+This is something that may eventually be added as a feature to dynamic_loader() itself.\r
+\r
+Similar approaches could be taken towards sets and dictionaries with non-string keys \r
+although the hash policy of the members would need to be distilled into a filter() criterion.\r
+\r
+"""\r
+\r
+class MyProxyDict(object):\r
+ def __init__(self, parent, collection_name, keyname):\r
+ self.parent = parent\r
+ self.collection_name = collection_name\r
+ self.keyname = keyname\r
+ \r
+ def collection(self):\r
+ return getattr(self.parent, self.collection_name)\r
+ collection = property(collection)\r
+ \r
+ def keys(self):\r
+ # this can be improved to not query all columns\r
+ return [getattr(x, self.keyname) for x in self.collection.all()]\r
+ \r
+ def __getitem__(self, key):\r
+ x = self.collection.filter_by(**{self.keyname:key}).first()\r
+ if x:\r
+ return x\r
+ else:\r
+ raise KeyError(key)\r
+\r
+ def __setitem__(self, key, value):\r
+ try:\r
+ existing = self[key]\r
+ self.collection.remove(existing)\r
+ except KeyError:\r
+ pass\r
+ self.collection.append(value)\r
+\r
+from sqlalchemy.ext.declarative import declarative_base\r
+from sqlalchemy import *\r
+from sqlalchemy.orm import *\r
+\r
+Base = declarative_base(engine=create_engine('sqlite://'))\r
+\r
+class MyParent(Base):\r
+ __tablename__ = 'parent'\r
+ id = Column(Integer, primary_key=True)\r
+ name = Column(String(50))\r
+ _collection = dynamic_loader("MyChild", cascade="all, delete-orphan")\r
+ \r
+ def child_map(self):\r
+ return MyProxyDict(self, '_collection', 'key')\r
+ child_map = property(child_map)\r
+ \r
+class MyChild(Base):\r
+ __tablename__ = 'child'\r
+ id = Column(Integer, primary_key=True)\r
+ key = Column(String(50))\r
+ parent_id = Column(Integer, ForeignKey('parent.id'))\r
+\r
+ \r
+Base.metadata.create_all()\r
+\r
+sess = create_session(autoflush=True, transactional=True)\r
+\r
+p1 = MyParent(name='p1')\r
+sess.save(p1)\r
+\r
+p1.child_map['k1'] = k1 = MyChild(key='k1')\r
+p1.child_map['k2'] = k2 = MyChild(key='k2')\r
+\r
+\r
+assert p1.child_map.keys() == ['k1', 'k2']\r
+\r
+assert p1.child_map['k1'] is k1\r
+\r
+p1.child_map['k2'] = k2b = MyChild(key='k2')\r
+assert p1.child_map['k2'] is k2b\r
+\r
+assert sess.query(MyChild).all() == [k1, k2b]\r
+\r