Hi Oleg,

On Wednesday 12 August 2009 10:06:30 Oleg Broytmann wrote:
> On Tue, Aug 11, 2009 at 07:40:12AM +0200, Tom Coetser wrote:
> > class Member(SQLObject):
> >     name = StringCol(alternateID=True)
> >     roles = SQLRelatedJoin('Role', intermediateTable='member_role',
> >                                createRelatedTable=False)
> >
> > class Role(SQLObject):
> >     name = StringCol(alternateID=True)
> >     members = SQLRelatedJoin('Member', intermediateTable='member_role',
> >                                createRelatedTable=False)
> >
> > class MemberRole(SQLObject):
> >     member = ForeignKey('Member', notNull=True, cascade=False)
> >     role = ForeignKey('Role', notNull=True, cascade=False)
> >
> > When I call destroySelf() on a member though, I would like to **not**
> > have that member deleted if it still has any roles assigned to it. I
> > tried setting the cascade=False option in the intermediate table, but
> > this does not help because it looks like the base destroySelf() method
> > automatically deletes any RelatedJoins.
>
>    First thing I can guess your are using a backend that doesn't support
> CASCADE (SQLite?) With SQLite, you can CREATE a TRIGGER to prevent deletion

No, I am using Postgres after burning my fingers during the testing stages 
with exactly this using SQLite.

> from the intermediate table, but you have to do it yourself.
>    .destroySelf() actually doesn't rely on the backend support for CASCADE;
> instead it uses it itself, but not on the RelatedJoin's intermediate table
> even if the table is declared explicitly. The simplest way I see is to
> override .destroySelf:
>
> class Member(SQLObject):
>     name = StringCol(alternateID=True)
>     roles = SQLRelatedJoin('Role', intermediateTable='member_role',
>                                createRelatedTable=False)
>
>     def destroySelf(self):
>         if list(self.roles): # or self.roles.count()
>             raise RuntimeError('Cannot delete a member (%s) that has roles'
> % self.id)
>         super(Member, self).destroySelf()
>
> class Role(SQLObject):
>     name = StringCol(alternateID=True)
>     members = SQLRelatedJoin('Member', intermediateTable='member_role',
>                                createRelatedTable=False)
>
>     def destroySelf(self):
>         try:
>             self.members[0]
>         except IndexError:
>             super(Role, self).destroySelf()
>         else:
>             raise RuntimeError('Cannot delete a role (%s) that has members'
> % self.id)
>
>    I showed three different ways to check for RelatedJoin. This of course
> only works with .destroySelf - other means will happily delete rows.

Thanks. Yes, I did end up overriding .destroySelf() and that seems to work 
fine. The other methods of deleting records are handled directly by the 
backend via the cascade=False on the ForeignKeys on the intermediate table.

The only awkward part is that exception handling is a bit weird due to 
different exceptions being raised for essentially the same reason but using 
different delete methods. But for now I can live with this :-)

Thanks for the help.


Cheers,
  Tom

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
sqlobject-discuss mailing list
sqlobject-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss

Reply via email to