Source code for examples.dynamic_dict.dynamic_dict

  1. from sqlalchemy import Column
  2. from sqlalchemy import create_engine
  3. from sqlalchemy import ForeignKey
  4. from sqlalchemy import Integer
  5. from sqlalchemy import String
  6. from sqlalchemy.ext.declarative import declarative_base
  7. from sqlalchemy.orm import relationship
  8. from sqlalchemy.orm import sessionmaker
  9. class ProxyDict(object):
  10. def __init__(self, parent, collection_name, childclass, keyname):
  11. self.parent = parent
  12. self.collection_name = collection_name
  13. self.childclass = childclass
  14. self.keyname = keyname
  15. @property
  16. def collection(self):
  17. return getattr(self.parent, self.collection_name)
  18. def keys(self):
  19. descriptor = getattr(self.childclass, self.keyname)
  20. return [x[0] for x in self.collection.values(descriptor)]
  21. def __getitem__(self, key):
  22. x = self.collection.filter_by(**{self.keyname: key}).first()
  23. if x:
  24. return x
  25. else:
  26. raise KeyError(key)
  27. def __setitem__(self, key, value):
  28. try:
  29. existing = self[key]
  30. self.collection.remove(existing)
  31. except KeyError:
  32. pass
  33. self.collection.append(value)
  34. engine = create_engine("sqlite://", echo=True)
  35. Base = declarative_base(engine)
  36. class Parent(Base):
  37. __tablename__ = "parent"
  38. id = Column(Integer, primary_key=True)
  39. name = Column(String(50))
  40. _collection = relationship(
  41. "Child", lazy="dynamic", cascade="all, delete-orphan"
  42. )
  43. @property
  44. def child_map(self):
  45. return ProxyDict(self, "_collection", Child, "key")
  46. class Child(Base):
  47. __tablename__ = "child"
  48. id = Column(Integer, primary_key=True)
  49. key = Column(String(50))
  50. parent_id = Column(Integer, ForeignKey("parent.id"))
  51. def __repr__(self):
  52. return "Child(key=%r)" % self.key
  53. Base.metadata.create_all()
  54. sess = sessionmaker()()
  55. p1 = Parent(name="p1")
  56. sess.add(p1)
  57. print("\n---------begin setting nodes, autoflush occurs\n")
  58. p1.child_map["k1"] = Child(key="k1")
  59. p1.child_map["k2"] = Child(key="k2")
  60. # this will autoflush the current map.
  61. # ['k1', 'k2']
  62. print("\n---------print keys - flushes first\n")
  63. print(list(p1.child_map.keys()))
  64. # k1
  65. print("\n---------print 'k1' node\n")
  66. print(p1.child_map["k1"])
  67. print("\n---------update 'k2' node - must find existing, and replace\n")
  68. p1.child_map["k2"] = Child(key="k2")
  69. print("\n---------print 'k2' key - flushes first\n")
  70. # k2
  71. print(p1.child_map["k2"])
  72. print("\n---------print all child nodes\n")
  73. # [k1, k2b]
  74. print(sess.query(Child).all())