"""The datamodel, which represents Person that has multipleAddress objects, each with PostalCode, City, Country.Person --(1..n)--> AddressAddress --(has a)--> PostalCodePostalCode --(has a)--> CityCity --(has a)--> Country"""fromsqlalchemyimportColumnfromsqlalchemyimportForeignKeyfromsqlalchemyimportIntegerfromsqlalchemyimportStringfromsqlalchemy.ormimportrelationshipfrom.caching_queryimportRelationshipCachefrom.environmentimportBasefrom.environmentimportbootstrapclassCountry(Base):__tablename__="country"id=Column(Integer,primary_key=True)name=Column(String(100),nullable=False)def__init__(self,name):self.name=nameclassCity(Base):__tablename__="city"id=Column(Integer,primary_key=True)name=Column(String(100),nullable=False)country_id=Column(Integer,ForeignKey("country.id"),nullable=False)country=relationship(Country)def__init__(self,name,country):self.name=nameself.country=countryclassPostalCode(Base):__tablename__="postal_code"id=Column(Integer,primary_key=True)code=Column(String(10),nullable=False)city_id=Column(Integer,ForeignKey("city.id"),nullable=False)city=relationship(City)@propertydefcountry(self):returnself.city.countrydef__init__(self,code,city):self.code=codeself.city=cityclassAddress(Base):__tablename__="address"id=Column(Integer,primary_key=True)person_id=Column(Integer,ForeignKey("person.id"),nullable=False)street=Column(String(200),nullable=False)postal_code_id=Column(Integer,ForeignKey("postal_code.id"))postal_code=relationship(PostalCode)@propertydefcity(self):returnself.postal_code.city@propertydefcountry(self):returnself.postal_code.countrydef__str__(self):return"%s\t%s, %s\t%s"%(self.street,self.city.name,self.postal_code.code,self.country.name,)classPerson(Base):__tablename__="person"id=Column(Integer,primary_key=True)name=Column(String(100),nullable=False)addresses=relationship(Address,collection_class=set)def__init__(self,name,*addresses):self.name=nameself.addresses=set(addresses)def__str__(self):returnself.namedef__repr__(self):return"Person(name=%r)"%self.namedefformat_full(self):return"\t".join([str(x)forxin[self]+list(self.addresses)])# Caching options. A set of three RelationshipCache options# which can be applied to Query(), causing the "lazy load"# of these attributes to be loaded from cache.cache_address_bits=(RelationshipCache(PostalCode.city,"default").and_(RelationshipCache(City.country,"default")).and_(RelationshipCache(Address.postal_code,"default")))bootstrap()