Please note: this project is inactive since early 2006

 
2.6.3.2 A short example

Now that we now how many-to-many relationships are handled, we know what we should do:

  1. define the correlation table as an entity in the model,

  2. connect the two tables to the correlation table and back,

  3. because we do not want to directly manipulate objects coming from the correlation table, we will write some code so that we can directly access persons from a given address, and addresses from a given person;

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
Hosted by:SourceForge.net Logo