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