Now that we now how many-to-many relationships are handled, we know what we should do:
We've seen in the previous how the model looks like with the correlation table. Here is the full PyModel:
from Modeling.PyModel import * # defaults AString.defaults['width'] = 40 Entity.defaults['properties'] = [ APrimaryKey('id', isClassProperty=0, isRequired=1, doc='PK') ] ## _connDict = {'database': 'MM1', 'user': 'postgres', 'host': 'localhost', 'password': ''} model = Model('MM1',adaptorName='Postgresql',connDict=_connDict) model.version='0.1' model.entities = [ Entity('Person', properties=[ AString('name',isRequired=1) ] ), Entity('Address', properties=[ AString('street', isRequired=1), AString('town') ] ), Entity('PersonAddress'), ] #--- model.associations=[ Association('PersonAddress','Person', relations=['person','personAddresses'], delete=['nullify','cascade'] ), Association('PersonAddress','Address', relations=['address','personAddresses'], delete=['nullify','deny'] ), ]
We just defined a new entity, PersonAddress, and two associations modeling the relationships between the correlation table and the correlated ones.
Last, we'll need to add some code in classes Person and Address
to directly manipulate the many-to-many relationships. Since relating an
object to an other one is just a matter of adding a object/a row to the
correlation table, the code is pretty straightforward.
In Person, you'll add the following methods:
# Relationship: addresses def getAddresses(self): return self.valueForKeyPath('personAddresses.address') def addToAddresses(self, address): if address in self.getAddresses(): return from PersonAddress import PersonAddress _pa=PersonAddress() # Create an object in the correlation table self.editingContext().insert(_pa) self.addToPersonAddresses(_pa) _pa.setPerson(self) _pa.setAddress(address) address.addToPersonAddresses(_pa) def removeFromAddresses(self, address): _pa=[pa for pa in self.getPersonAddresses() if address == pa.getAddress()] if not _pa: raise ValueError, 'Cannot find address' # Here we simply need to remove the corresponding object in the # correlation table _pa=_pa[0] self.removeFromPersonAddresses(_pa) _pa.getAddress().removeFromPersonAddresses(_pa) _pa.setAddress(None) _pa.setPerson(None) self.editingContext().delete(_pa)
And you'll add the equivalent methods in Address:
# Relationship: persons def getPersons(self): return self.valueForKeyPath('personAddresses.person') def addToPersons(self, person): if person in self.getPersons(): return from PersonAddress import PersonAddress _pa=PersonAddress() # Create an object in the correlation table self.editingContext().insert(_pa) self.addToPersonAddresses(_pa) _pa.setPerson(person) _pa.setAddress(self) person.addToPersonAddresses(_pa) def removeFromPersons(self, person): _pa=[pa for pa in self.getPersonAddresses() if person == pa.getPerson()] if not _pa: raise ValueError, 'Cannot find person' # Here we simply need to remove the corresponding object in the # correlation table _pa=_pa[0] self.removeFromPersonAddresses(_pa) _pa.getPerson().removeFromPersonAddresses(_pa) _pa.setAddress(None) _pa.setPerson(None) self.editingContext().delete(_pa)
Now we can normally call e.g. getAddresses or addToAddresses on a Person object, passing a Address object, without caring about the details anymore.
Comments are welcome: Sebastien Bigaret / Modeling Home Page