+++ /dev/null
-"""illlustrates techniques for dealing with very large collections.
-
-Also see the docs regarding the new "dynamic" relation option, which
-presents a more refined version of some of these patterns.
-"""
-
-from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
-from sqlalchemy.orm import (mapper, relation, create_session, MapperExtension,
- object_session)
-
-meta = MetaData('sqlite://')
-meta.bind.echo = True
-
-org_table = Table('organizations', meta,
- Column('org_id', Integer, primary_key=True),
- Column('org_name', String(50), nullable=False, key='name'),
- mysql_engine='InnoDB')
-
-member_table = Table('members', meta,
- Column('member_id', Integer, primary_key=True),
- Column('member_name', String(50), nullable=False, key='name'),
- Column('org_id', Integer, ForeignKey('organizations.org_id')),
- mysql_engine='InnoDB')
-meta.create_all()
-
-class Organization(object):
- def __init__(self, name):
- self.name = name
- member_query = property(lambda self:object_session(self).query(Member).with_parent(self),
- doc="""locate a subset of the members associated with this Organization""")
-
-class Member(object):
- def __init__(self, name):
- self.name = name
-
-# note that we can also place "ON DELETE CASCADE" on the tables themselves,
-# instead of using this extension
-class DeleteMemberExt(MapperExtension):
- """will delete child Member objects in one pass when Organizations are deleted"""
- def before_delete(self, mapper, connection, instance):
- connection.execute(member_table.delete(member_table.c.org_id==instance.org_id))
-
-mapper(Organization, org_table, extension=DeleteMemberExt(), properties = {
- # set up the relationship with "lazy=None" so no loading occurs (even lazily),
- # "cascade='all, delete-orphan'" to declare Member objects as local to their parent Organization,
- # "passive_deletes=True" so that the "delete, delete-orphan" cascades do not load in the child objects
- # upon deletion
- 'members' : relation(Member, lazy=None, passive_deletes=True, cascade="all, delete-orphan")
-})
-
-mapper(Member, member_table)
-
-sess = create_session()
-
-# create org with some members
-org = Organization('org one')
-org.members.append(Member('member one'))
-org.members.append(Member('member two'))
-org.members.append(Member('member three'))
-
-sess.add(org)
-
-print "-------------------------\nflush one - save org + 3 members"
-sess.flush()
-sess.expunge_all()
-
-# reload. load the org and some child members
-print "-------------------------\nload subset of members"
-org = sess.query(Organization).get(org.org_id)
-members = org.member_query.filter(member_table.c.name.like('%member t%')).all()
-print members
-
-sess.expunge_all()
-
-
-# reload. create some more members and flush, without loading any of the original members
-org = sess.query(Organization).get(org.org_id)
-org.members.append(Member('member four'))
-org.members.append(Member('member five'))
-org.members.append(Member('member six'))
-
-print "-------------------------\nflush two - save 3 more members"
-sess.flush()
-
-sess.expunge_all()
-org = sess.query(Organization).get(org.org_id)
-
-# now delete. note that this will explictily delete members four, five and six because they are in the session,
-# but will not issue individual deletes for members one, two and three, nor will it load them.
-sess.delete(org)
-print "-------------------------\nflush three - delete org, delete members in one statement"
-sess.flush()
-
--- /dev/null
+"""Large collection example.
+
+Illustrates the options to use on relation() when the list of related objects
+is very large.
+
+"""
+
+from sqlalchemy import (MetaData, Table, Column, Integer, String, ForeignKey,
+ create_engine)
+from sqlalchemy.orm import (mapper, relation, sessionmaker)
+
+
+meta = MetaData()
+
+org_table = Table('organizations', meta,
+ Column('org_id', Integer, primary_key=True),
+ Column('org_name', String(50), nullable=False, key='name'),
+ mysql_engine='InnoDB')
+
+member_table = Table('members', meta,
+ Column('member_id', Integer, primary_key=True),
+ Column('member_name', String(50), nullable=False, key='name'),
+ Column('org_id', Integer, ForeignKey('organizations.org_id', ondelete="CASCADE")),
+ mysql_engine='InnoDB')
+
+
+class Organization(object):
+ def __init__(self, name):
+ self.name = name
+
+class Member(object):
+ def __init__(self, name):
+ self.name = name
+
+mapper(Organization, org_table, properties = {
+ 'members' : relation(Member,
+ # Organization.members will be a Query object - no loading
+ # of the entire collection occurs unless requested
+ lazy="dynamic",
+
+ # Member objects "belong" to their parent, are deleted when
+ # removed from the collection
+ cascade="all, delete-orphan",
+
+ # "delete, delete-orphan" cascade does not load in objects on delete,
+ # allows ON DELETE CASCADE to handle it.
+ # this only works with a database that supports ON DELETE CASCADE -
+ # *not* sqlite or MySQL with MyISAM
+ passive_deletes=True,
+ )
+})
+
+mapper(Member, member_table)
+
+if __name__ == '__main__':
+ engine = create_engine("mysql://scott:tiger@localhost/test", echo=True)
+ meta.create_all(engine)
+
+ # expire_on_commit=False means the session contents
+ # will not get invalidated after commit.
+ sess = sessionmaker(engine, expire_on_commit=False)()
+
+ # create org with some members
+ org = Organization('org one')
+ org.members.append(Member('member one'))
+ org.members.append(Member('member two'))
+ org.members.append(Member('member three'))
+
+ sess.add(org)
+
+ print "-------------------------\nflush one - save org + 3 members\n"
+ sess.commit()
+
+ # the 'members' collection is a Query. it issues
+ # SQL as needed to load subsets of the collection.
+ print "-------------------------\nload subset of members\n"
+ members = org.members.filter(member_table.c.name.like('%member t%')).all()
+ print members
+
+ # new Members can be appended without any
+ # SQL being emitted to load the full collection
+ org.members.append(Member('member four'))
+ org.members.append(Member('member five'))
+ org.members.append(Member('member six'))
+
+ print "-------------------------\nflush two - save 3 more members\n"
+ sess.commit()
+
+ # delete the object. Using ON DELETE CASCADE
+ # SQL is only emitted for the head row - the Member rows
+ # disappear automatically without the need for additional SQL.
+ sess.delete(org)
+ print "-------------------------\nflush three - delete org, delete members in one statement\n"
+ sess.commit()
+
+ print "-------------------------\nno Member rows should remain:\n"
+ print sess.query(Member).count()
+
+ print "------------------------\ndone. dropping tables."
+ meta.drop_all(engine)
\ No newline at end of file