From: Mike Bayer Date: Mon, 18 Jan 2010 20:58:34 +0000 (+0000) Subject: updated the large_collection example to modern SQLA. X-Git-Tag: rel_0_6beta1~58 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8a9e2a6c3783433c6b1c7c6a3d6ffd2cc7c1fd16;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git updated the large_collection example to modern SQLA. --- diff --git a/examples/README b/examples/README deleted file mode 100644 index bb4b953354..0000000000 --- a/examples/README +++ /dev/null @@ -1,2 +0,0 @@ -placeholder - diff --git a/examples/collections/large_collection.py b/examples/collections/large_collection.py deleted file mode 100644 index 2451ea5826..0000000000 --- a/examples/collections/large_collection.py +++ /dev/null @@ -1,93 +0,0 @@ -"""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() - diff --git a/examples/collections/__init__.py b/examples/large_collection/__init__.py similarity index 100% rename from examples/collections/__init__.py rename to examples/large_collection/__init__.py diff --git a/examples/large_collection/large_collection.py b/examples/large_collection/large_collection.py new file mode 100644 index 0000000000..4d98eed2b4 --- /dev/null +++ b/examples/large_collection/large_collection.py @@ -0,0 +1,100 @@ +"""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