diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-04-27 22:33:37 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-04-27 22:33:37 -0400 |
| commit | d03226426c24eef5c9e19822ff07a5f72dd5379f (patch) | |
| tree | 4d4520085485e397f11c23248733bab1e30dfd7e /examples/poly_assoc | |
| parent | 7df21e5a1f252ff768f684132db95bd1b5e78efa (diff) | |
| download | sqlalchemy-d03226426c24eef5c9e19822ff07a5f72dd5379f.tar.gz | |
- removed the ancient "polymorphic association"
examples and replaced with an updated set of
examples that use declarative mixins,
"generic_associations". Each presents an alternative
table layout.
Diffstat (limited to 'examples/poly_assoc')
| -rw-r--r-- | examples/poly_assoc/__init__.py | 10 | ||||
| -rw-r--r-- | examples/poly_assoc/poly_assoc.py | 156 | ||||
| -rw-r--r-- | examples/poly_assoc/poly_assoc_fk.py | 164 | ||||
| -rw-r--r-- | examples/poly_assoc/poly_assoc_generic.py | 161 |
4 files changed, 0 insertions, 491 deletions
diff --git a/examples/poly_assoc/__init__.py b/examples/poly_assoc/__init__.py deleted file mode 100644 index 19836a742..000000000 --- a/examples/poly_assoc/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -Illustrates polymorphic associations, a method of associating a particular child object with many different types of parent object. - -This example is based off the original blog post at `<http://techspot.zzzeek.org/?p=13>`_ and illustrates three techniques: - -* ``poly_assoc.py`` - imitates the non-foreign-key schema used by Ruby on Rails' Active Record. -* ``poly_assoc_fk.py`` - Adds a polymorphic association table so that referential integrity can be maintained. -* ``poly_assoc_generic.py`` - further automates the approach of ``poly_assoc_fk.py`` to also generate the association table definitions automatically. - -"""
\ No newline at end of file diff --git a/examples/poly_assoc/poly_assoc.py b/examples/poly_assoc/poly_assoc.py deleted file mode 100644 index 1854bfa3d..000000000 --- a/examples/poly_assoc/poly_assoc.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -"polymorphic" associations, ala ActiveRecord. - -In this example, we are specifically targeting this ActiveRecord -functionality: - -http://wiki.rubyonrails.org/rails/pages/UnderstandingPolymorphicAssociations - -The term "polymorphic" here means "object X can be referenced by objects A, B, -and C, along a common line of association". - -In this example we illustrate the relationship in both directions. A little -bit of property magic is used to smooth the edges. - -AR creates this relationship in such a way that disallows any foreign key -constraint from existing on the association. For a different way of doing -this, see poly_assoc_fks.py. The interface is the same, the efficiency is more -or less the same, but foreign key constraints may be used. That example also -better separates the associated target object from those which associate with -it. - -""" - -from sqlalchemy import MetaData, Table, Column, Integer, String, and_ -from sqlalchemy.orm import mapper, relationship, sessionmaker, \ - class_mapper, backref - -metadata = MetaData('sqlite://') - -####### -# addresses table, class, 'addressable interface'. - -addresses = Table("addresses", metadata, - Column('id', Integer, primary_key=True), - Column('addressable_id', Integer), - Column('addressable_type', String(50)), - Column('street', String(100)), - Column('city', String(50)), - Column('country', String(50)) - ) - -class Address(object): - def __init__(self, type): - self.addressable_type = type - @property - def member(self): - return getattr(self, '_backref_%s' % self.addressable_type) - -def addressable(cls, name, uselist=True): - """addressable 'interface'. - - if you really wanted to make a "generic" version of this function, it's - straightforward. - """ - - # create_address function, imitaes the rails example. - # we could probably use property tricks as well to set - # the Address object's "addressabletype" attribute. - def create_address(self): - a = Address(table.name) - if uselist: - getattr(self, name).append(a) - else: - setattr(self, name, a) - return a - - mapper = class_mapper(cls) - table = mapper.local_table - cls.create_address = create_address - # no constraints. therefore define constraints in an ad-hoc fashion. - primaryjoin = and_( - list(table.primary_key)[0] == addresses.c.addressable_id, - addresses.c.addressable_type == table.name - ) - foreign_keys = [addresses.c.addressable_id] - mapper.add_property(name, relationship( - Address, - primaryjoin=primaryjoin, - uselist=uselist, - foreign_keys=foreign_keys, - backref=backref('_backref_%s' % table.name, - primaryjoin=list(table.primary_key)[0] ==\ - addresses.c.addressable_id, - foreign_keys=foreign_keys) - ) - ) - -mapper(Address, addresses) - -###### -# sample # 1, users - -users = Table("users", metadata, - Column('id', Integer, primary_key=True), - Column('name', String(50), nullable=False) - ) - -class User(object): - pass - -mapper(User, users) -addressable(User, 'addresses', uselist=True) - -###### -# sample # 2, orders - -orders = Table("orders", metadata, - Column('id', Integer, primary_key=True), - Column('description', String(50), nullable=False)) - -class Order(object): - pass - -mapper(Order, orders) -addressable(Order, 'address', uselist=False) - - -###### -# use it ! -metadata.create_all() - -u1 = User() -u1.name = 'bob' - -o1 = Order() -o1.description = 'order 1' - -a1 = u1.create_address() -a1.street = '123 anywhere street' -a2 = u1.create_address() -a2.street = '345 orchard ave' - -a3 = o1.create_address() -a3.street = '444 park ave.' - -sess = sessionmaker()() -sess.add(u1) -sess.add(o1) - -sess.commit() - -# query objects, get their addresses - -bob = sess.query(User).filter_by(name='bob').one() -assert [s.street for s in bob.addresses] == ['123 anywhere street', '345 orchard ave'] - -order = sess.query(Order).filter_by(description='order 1').one() -assert order.address.street == '444 park ave.' - -# query from Address to members - -for address in sess.query(Address).all(): - print "Street", address.street, "Member", address.member - - - diff --git a/examples/poly_assoc/poly_assoc_fk.py b/examples/poly_assoc/poly_assoc_fk.py deleted file mode 100644 index a22020e08..000000000 --- a/examples/poly_assoc/poly_assoc_fk.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -"polymorphic" associations, ala SQLAlchemy. - -See "poly_assoc.py" for an imitation of this functionality as implemented in -ActiveRecord. - -Here, we build off the previous example, adding an association table that -allows the relationship to be expressed as a many-to-one from the "model" -object to its "association", so that each model table bears the foreign key -constraint. This allows the same functionality via traditional normalized form -with full constraints. It also isolates the target associated object from its -method of being associated, allowing greater flexibility in its usage. - -As in the previous example, a little bit of property magic is used to smooth -the edges. - -For a more genericized version of this example, see poly_assoc_generic.py. -""" - -from sqlalchemy import MetaData, Table, Column, Integer, String, \ - ForeignKey -from sqlalchemy.orm import mapper, relationship, sessionmaker, \ - class_mapper - -metadata = MetaData('sqlite://') - -####### -# addresses table, class, 'addressable interface'. - -addresses = Table("addresses", metadata, - Column('id', Integer, primary_key=True), - Column('assoc_id', None, ForeignKey('address_associations.assoc_id')), - Column('street', String(100)), - Column('city', String(50)), - Column('country', String(50)) - ) - -## association table -address_associations = Table("address_associations", metadata, - Column('assoc_id', Integer, primary_key=True), - Column('type', String(50), nullable=False) -) - -class Address(object): - - @property - def member(self): - return getattr(self.association, '_backref_%s' - % self.association.type) - -class AddressAssoc(object): - def __init__(self, name): - self.type = name - -def addressable(cls, name, uselist=True): - """addressable 'interface'. - - we create this function here to imitate the style used in poly_assoc.py. - - """ - mapper = class_mapper(cls) - table = mapper.local_table - mapper.add_property('address_rel', - relationship(AddressAssoc, - backref='_backref_%s' % table.name) - ) - - if uselist: - # list based property decorator - def get(self): - if self.address_rel is None: - self.address_rel = AddressAssoc(table.name) - return self.address_rel.addresses - setattr(cls, name, property(get)) - else: - # scalar based property decorator - def get(self): - return self.address_rel.addresses[0] - def set(self, value): - if self.address_rel is None: - self.address_rel = AddressAssoc(table.name) - self.address_rel.addresses = [value] - setattr(cls, name, property(get, set)) - -mapper(Address, addresses) - -mapper(AddressAssoc, address_associations, properties={ - 'addresses':relationship(Address, backref='association'), -}) - -###### -# sample # 1, users - -users = Table("users", metadata, - Column('id', Integer, primary_key=True), - Column('name', String(50), nullable=False), - # this column ties the users table into the address association - Column('assoc_id', Integer, ForeignKey('address_associations.assoc_id')) - ) - -class User(object): - pass - -mapper(User, users) -addressable(User, 'addresses', uselist=True) - -###### -# sample # 2, orders - -orders = Table("orders", metadata, - Column('id', Integer, primary_key=True), - Column('description', String(50), nullable=False), - # this column ties the orders table into the address association - Column('assoc_id', Integer, ForeignKey('address_associations.assoc_id')) - ) - -class Order(object): - pass - -mapper(Order, orders) -addressable(Order, 'address', uselist=False) - -###### -# use it ! -metadata.create_all() - -u1 = User() -u1.name = 'bob' - -o1 = Order() -o1.description = 'order 1' - -# note we can just create an Address object freely. -# if you want a create_address() function, just stick it on the class. -a1 = Address() -u1.addresses.append(a1) -a1.street = '123 anywhere street' - -a2 = Address() -u1.addresses.append(a2) -a2.street = '345 orchard ave' - -o1.address = Address() -o1.address.street = '444 park ave.' - -sess = sessionmaker()() -sess.add(u1) -sess.add(o1) - -sess.commit() - -# query objects, get their addresses - -bob = sess.query(User).filter_by(name='bob').one() -assert [s.street for s in bob.addresses] == \ - ['123 anywhere street', '345 orchard ave'] - -order = sess.query(Order).filter_by(description='order 1').one() -assert order.address.street == '444 park ave.' - -# query from Address to members - -for address in sess.query(Address).all(): - print "Street", address.street, "Member", address.member diff --git a/examples/poly_assoc/poly_assoc_generic.py b/examples/poly_assoc/poly_assoc_generic.py deleted file mode 100644 index b674e1eb8..000000000 --- a/examples/poly_assoc/poly_assoc_generic.py +++ /dev/null @@ -1,161 +0,0 @@ -""" -"polymorphic" associations, ala SQLAlchemy. - -This example generalizes the function in poly_assoc_pk.py into a function -"association" which creates a new polymorphic association "interface". -""" - -from sqlalchemy import MetaData, Table, Column, Integer, String, \ - ForeignKey -from sqlalchemy.orm import mapper, relationship, sessionmaker, \ - class_mapper - -metadata = MetaData('sqlite://') - -def association(cls, table): - """create an association 'interface'.""" - - interface_name = table.name - attr_name = "%s_rel" % interface_name - - metadata = table.metadata - association_table = Table("%s_associations" % interface_name, metadata, - Column('assoc_id', Integer, primary_key=True), - Column('type', String(50), nullable=False) - ) - - class GenericAssoc(object): - def __init__(self, name): - self.type = name - - def interface(cls, name, uselist=True): - - mapper = class_mapper(cls) - table = mapper.local_table - mapper.add_property(attr_name, - relationship(GenericAssoc, - backref='_backref_%s' % table.name) - ) - - if uselist: - # list based property decorator - def get(self): - if getattr(self, attr_name) is None: - setattr(self, attr_name, GenericAssoc(table.name)) - return getattr(self, attr_name).targets - setattr(cls, name, property(get)) - else: - # scalar based property decorator - def get(self): - return getattr(self, attr_name).targets[0] - def set(self, value): - if getattr(self, attr_name) is None: - setattr(self, attr_name, GenericAssoc(table.name)) - getattr(self, attr_name).targets = [value] - setattr(cls, name, property(get, set)) - - @property - def member(self): - return getattr(self.association, - '_backref_%s' % self.association.type) - - setattr(cls, 'member', member) - - mapper(GenericAssoc, association_table, properties={ - 'targets':relationship(cls, backref='association'), - }) - - return interface - - -####### -# addresses table - -addresses = Table("addresses", metadata, - Column('id', Integer, primary_key=True), - Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id')), - Column('street', String(100)), - Column('city', String(50)), - Column('country', String(50)) - ) - -class Address(object): - pass - -# create "addressable" association -addressable = association(Address, addresses) - -mapper(Address, addresses) - - -###### -# sample # 1, users - -users = Table("users", metadata, - Column('id', Integer, primary_key=True), - Column('name', String(50), nullable=False), - Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id')) - ) - -class User(object): - pass - -mapper(User, users) - -# use the association -addressable(User, 'addresses', uselist=True) - -###### -# sample # 2, orders - -orders = Table("orders", metadata, - Column('id', Integer, primary_key=True), - Column('description', String(50), nullable=False), - Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id')) - ) - -class Order(object): - pass - -mapper(Order, orders) -addressable(Order, 'address', uselist=False) - -###### -# use it ! -metadata.create_all() - -u1 = User() -u1.name = 'bob' - -o1 = Order() -o1.description = 'order 1' - -a1 = Address() -u1.addresses.append(a1) -a1.street = '123 anywhere street' - -a2 = Address() -u1.addresses.append(a2) -a2.street = '345 orchard ave' - -o1.address = Address() -o1.address.street = '444 park ave.' - -sess = sessionmaker()() -sess.add(u1) -sess.add(o1) -sess.commit() - -# query objects, get their addresses - -bob = sess.query(User).filter_by(name='bob').one() -assert [s.street for s in bob.addresses] == \ - ['123 anywhere street', '345 orchard ave'] - -order = sess.query(Order).filter_by(description='order 1').one() -assert order.address.street == '444 park ave.' - -# query from Address to members - -for address in sess.query(Address).all(): - print "Street", address.street, "Member", address.member |
