diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-05-07 14:48:04 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-05-07 14:48:04 +0000 |
commit | 30f55a50165e56d79dfc5f720616d4d9cc400b33 (patch) | |
tree | fcd3ee4b8314e55129dff29ba8b8d1b59de2486a | |
parent | e435591259e874c5c93f17582a0a2e882525c320 (diff) | |
download | sqlalchemy-30f55a50165e56d79dfc5f720616d4d9cc400b33.tar.gz |
- added an example dynamic_dict/dynamic_dict.py, illustrating
a simple way to place dictionary behavior on top of
a dynamic_loader.
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | examples/dynamic_dict/dynamic_dict.py | 83 |
2 files changed, 87 insertions, 0 deletions
@@ -69,6 +69,10 @@ CHANGES their operands and only operate on sets, frozensets or subclasses of the collection type. Previously, they would accept any duck-typed set. + + - added an example dynamic_dict/dynamic_dict.py, illustrating + a simple way to place dictionary behavior on top of + a dynamic_loader. - sql - Added COLLATE support via the .collate(<collation>) diff --git a/examples/dynamic_dict/dynamic_dict.py b/examples/dynamic_dict/dynamic_dict.py new file mode 100644 index 000000000..682def78c --- /dev/null +++ b/examples/dynamic_dict/dynamic_dict.py @@ -0,0 +1,83 @@ +"""Illustrates how to place a dictionary-like facade on top of a dynamic_loader, so
+that dictionary operations (assuming simple string keys) can operate upon a large
+collection without loading the full collection at once.
+
+This is something that may eventually be added as a feature to dynamic_loader() itself.
+
+Similar approaches could be taken towards sets and dictionaries with non-string keys
+although the hash policy of the members would need to be distilled into a filter() criterion.
+
+"""
+
+class MyProxyDict(object):
+ def __init__(self, parent, collection_name, keyname):
+ self.parent = parent
+ self.collection_name = collection_name
+ self.keyname = keyname
+
+ def collection(self):
+ return getattr(self.parent, self.collection_name)
+ collection = property(collection)
+
+ def keys(self):
+ # this can be improved to not query all columns
+ return [getattr(x, self.keyname) for x in self.collection.all()]
+
+ def __getitem__(self, key):
+ x = self.collection.filter_by(**{self.keyname:key}).first()
+ if x:
+ return x
+ else:
+ raise KeyError(key)
+
+ def __setitem__(self, key, value):
+ try:
+ existing = self[key]
+ self.collection.remove(existing)
+ except KeyError:
+ pass
+ self.collection.append(value)
+
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import *
+from sqlalchemy.orm import *
+
+Base = declarative_base(engine=create_engine('sqlite://'))
+
+class MyParent(Base):
+ __tablename__ = 'parent'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(50))
+ _collection = dynamic_loader("MyChild", cascade="all, delete-orphan")
+
+ def child_map(self):
+ return MyProxyDict(self, '_collection', 'key')
+ child_map = property(child_map)
+
+class MyChild(Base):
+ __tablename__ = 'child'
+ id = Column(Integer, primary_key=True)
+ key = Column(String(50))
+ parent_id = Column(Integer, ForeignKey('parent.id'))
+
+
+Base.metadata.create_all()
+
+sess = create_session(autoflush=True, transactional=True)
+
+p1 = MyParent(name='p1')
+sess.save(p1)
+
+p1.child_map['k1'] = k1 = MyChild(key='k1')
+p1.child_map['k2'] = k2 = MyChild(key='k2')
+
+
+assert p1.child_map.keys() == ['k1', 'k2']
+
+assert p1.child_map['k1'] is k1
+
+p1.child_map['k2'] = k2b = MyChild(key='k2')
+assert p1.child_map['k2'] is k2b
+
+assert sess.query(MyChild).all() == [k1, k2b]
+
|