Source code for examples.generic_associations.table_per_related
"""Illustrates a generic association which persists associationobjects within individual tables, each one generated to persistthose objects on behalf of a particular parent class.This configuration has the advantage that each type of parentmaintains its "Address" rows separately, so that collectionsize for one type of parent will have no impact on other typesof parent. Navigation between parent and "Address" is simple,direct, and bidirectional.This recipe is the most efficient (speed wise and storage wise)and simple of all of them.The creation of many related tables may seem at first like an issuebut there really isn't any - the management and targeting of these tablesis completely automated."""fromsqlalchemyimportColumnfromsqlalchemyimportcreate_enginefromsqlalchemyimportForeignKeyfromsqlalchemyimportIntegerfromsqlalchemyimportStringfromsqlalchemy.ext.declarativeimportas_declarativefromsqlalchemy.ext.declarativeimportdeclared_attrfromsqlalchemy.ormimportrelationshipfromsqlalchemy.ormimportSession@as_declarative()classBase:"""Base class which provides automated table name and surrogate primary key column. """@declared_attrdef__tablename__(cls):returncls.__name__.lower()id=Column(Integer,primary_key=True)classAddress:"""Define columns that will be present in each 'Address' table. This is a declarative mixin, so additional mapped attributes beyond simple columns specified here should be set up using @declared_attr. """street=Column(String)city=Column(String)zip=Column(String)def__repr__(self):return"%s(street=%r, city=%r, zip=%r)"%(self.__class__.__name__,self.street,self.city,self.zip,)classHasAddresses:"""HasAddresses mixin, creates a new Address class for each parent. """@declared_attrdefaddresses(cls):cls.Address=type("%sAddress"%cls.__name__,(Address,Base),dict(__tablename__="%s_address"%cls.__tablename__,parent_id=Column(Integer,ForeignKey("%s.id"%cls.__tablename__)),parent=relationship(cls),),)returnrelationship(cls.Address)classCustomer(HasAddresses,Base):name=Column(String)classSupplier(HasAddresses,Base):company_name=Column(String)engine=create_engine("sqlite://",echo=True)Base.metadata.create_all(engine)session=Session(engine)session.add_all([Customer(name="customer 1",addresses=[Customer.Address(street="123 anywhere street",city="New York",zip="10110"),Customer.Address(street="40 main street",city="San Francisco",zip="95732"),],),Supplier(company_name="Ace Hammers",addresses=[Supplier.Address(street="2569 west elm",city="Detroit",zip="56785")],),])session.commit()forcustomerinsession.query(Customer):foraddressincustomer.addresses:print(address)print(address.parent)